Skip to content

Decouple the chained-emitter tests from the shipped particle vocabulary - #378

Merged
derek73 merged 2 commits into
masterfrom
claude/360-emitter-test-decoupling
Aug 15, 2026
Merged

Decouple the chained-emitter tests from the shipped particle vocabulary#378
derek73 merged 2 commits into
masterfrom
claude/360-emitter-test-decoupling

Conversation

@derek73

@derek73 derek73 commented Aug 14, 2026

Copy link
Copy Markdown
Owner

Groundwork for #360, which we didn't want blocked on a vocabulary/test coupling. It turned out the coupling was never real, and the guard that enforced it was asserting the wrong set.

Two commits: the sweep, and the fixes from a review that found the sweep half-done. Both are described below.

The guard asserted the wrong intersection

test_the_chained_emitter_is_still_reachable required a lead word in titles & particles_ambiguous. What the emitter actually requires, measured against "Freiherr von Richthofen" one membership at a time:

lexicon chain fork reported
shipped yes on von, from _group
freiherr out of particles nogiven='von' on von, from _assign
freiherr out of titles yesfamily='von Richthofen' on Freiherr, from _assign
von out of particles_ambiguous yes none

So the two memberships buy different things: particles is what produces the chain, titles is what the emitter's all(title(x) for x in range(k)) guard needs to report it — the merge() sits outside that guard. Both intersections are ['do','freiherr','st'] today, which is why the wrong set read as correct.

#360 cannot empty the right one. Curation moves words between the may-be-given and never-given halves; both are subsets of particles, so particle membership survives either way. The emitter was never at risk.

The coupling was unnecessary anyway

Reachability is a property of the emitter, not of the shipped word lists. A caller can configure the overlap themselves — Lexicon asserts no invariant against it and construction warns about nothing:

Zzt van Johnson, 'zzt' as title only                  -> given='van'  family='Johnson'      (_assign's half)
Zzt van Johnson, 'zzt' in titles+particles            -> given=''     family='van Johnson'  (_group's half)

An empty shipped intersection would leave the emitter reachable and merely unexercised by default. The old guard's remediation advice — "remove the emitter rather than repointing them" — would have deleted live code on a false signal.

What changed

The emitter tests supply their memberships instead of borrowing them, split by the role each word plays:

  • _TITLE_PARTICLES — the leading words, given titles + particles
  • _CHAINED_PARTICLES — the chained words (von, van), given particles_ambiguous

test_the_chained_emitter_is_reachable_by_construction carries three controls, one per membership the claim rests on: drop the leading word's particles and the chain goes; drop the chained word's particles_ambiguous and the report goes; drop the leading word's particles_ambiguous and nothing moves. That third one is the correction made executable — it is the membership the old guard asserted, and it buys the emitter nothing.

tests/v2/test_properties.py carried the same borrow on a larger surface: its "Freiherr " lead feeds a sweep over every ambiguous particle, and if that lead goes transparent the _group shapes leave the sweep while it keeps passing. Supplied there too.

Shipped-vocabulary behavior stays pinned where it belongs — tests/v2/cases.py's Freiherr von Richthofen row. Note that row tracks the parse, not the memberships: moving freiherr between the particle halves leaves it green, which is correct.

Review round

A three-agent review (test coverage, comment accuracy, general) found the first commit half-done, and found the comment block claiming otherwise. All fixed in the second commit:

  • the chained word was still borrowedvon/van came from the shipped lexicon, so moving them to never-given failed seven of these tests, the exact breakage the commit set out to prevent
  • the fixture repeated the error — it added the leading word to all three sets, so nothing could contradict the wrong precondition; measured, that third membership is inert
  • "drop it from either and there is no chain" was false for the titles half (see the table above)
  • the new docstring opened with "both a title and an ambiguous particle" — verbatim the wrong set the commit exists to retire
  • _overlap_parser's rationale cited 'Do St Johnson', which no test in the file parses

Verification

condition result
full suite 3197 passed, 41 skipped, 11 xfailed
tests/v2/test_parser.py 91 passed, 1 xfailed
leading word out of titles+particles only the cases.py tripwire fires
chained words moved to never-given no test in this diff fails
_group's emitter suppressed 6 failed — still sensitive

Every simulation asserts it took effect before running, so none is a no-op measurement. ruff check and mypy clean.

Two tests outside this diff still borrow van's ambiguity — test_parsedname_repr_includes_ambiguities_line and test_leading_particle_detail_names_the_role_it_got. Left alone deliberately: they fail loudly with an obvious fix (repoint to another ambiguous particle), which is not the failure mode this PR is about.

Groundwork for #360.

🤖 Generated with Claude Code

The _group PARTICLE_OR_GIVEN tests borrowed their precondition from the
shipped vocabulary, which coupled them to #360's curation. Two things
turned out to be wrong with that, both measured against "Freiherr von
Richthofen":

The guard asserted the wrong set. It required a lead word in
`titles & particles_ambiguous`; the emitter requires
`titles & PARTICLES`:

  freiherr out of particles_ambiguous only   -> still chains
  freiherr out of particles entirely         -> no chain
  freiherr out of titles only                -> no chain

The two intersections are the same three words today, which is why it
read as correct. And #360 cannot empty the right one: it moves words
between the may-be-given and never-given halves, both subsets of
particles, so particle membership survives either way.

The coupling was unnecessary regardless. Reachability is a property of
the emitter -- a caller may configure a titles/particles overlap
themselves, with no invariant against it and no warning -- so an empty
shipped intersection would leave the emitter reachable and merely
unexercised by default. The old guard's advice to "remove the emitter
rather than repointing them" would have deleted live code.

Tests now supply the memberships. The new reachability test carries two
controls, one per role: a plain-title lead (no chain, _assign reports
instead) and an unambiguous chained word (chain fires, nothing to
report) -- so a pass cannot be the grouping it would have produced
anyway. Verified:

  normal                         91 passed
  shipped overlap emptied        91 passed   (decoupled)
  emitter suppressed              6 failed   (still sensitive)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@derek73 derek73 added this to the v2.2 milestone Aug 14, 2026
@derek73 derek73 added the tests label Aug 14, 2026
@derek73 derek73 self-assigned this Aug 14, 2026
@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.51%. Comparing base (5320a42) to head (ef43b83).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #378   +/-   ##
=======================================
  Coverage   98.51%   98.51%           
=======================================
  Files          44       44           
  Lines        2895     2895           
=======================================
  Hits         2852     2852           
  Misses         43       43           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Review of the previous commit found it half-done, and found the comment
block claiming otherwise.

The emitter asks two things of two different words. The leading word
needs titles & particles; the chained word needs particles_ambiguous.
_overlap_parser supplied only the first, so the tests stayed coupled to
#360 through 'von'/'van' -- moving those to the never-given half failed
seven of them, which is the exact breakage the commit set out to
prevent. Constants are now split by role and both halves are supplied.

Three claims in that block were also wrong:

  "drop it from either and there is no chain" -- false for the titles
  half. Measured, freiherr out of titles: family='von Richthofen', so
  the chain is intact; what is lost is the REPORT, because the merge
  sits outside the all(title(x)) guard, and _assign then reports a fork
  about 'Freiherr' instead.

  the new test's docstring opened with "both a title and an ambiguous
  particle" -- verbatim the wrong set the block twenty lines above
  exists to retire.

  _overlap_parser's rationale cited 'Do St Johnson', which no test in
  the file parses; the string lives only in comments.

The fixture repeated the docstring's error: it added the leading word to
all three sets, so nothing could contradict the wrong precondition.
Measured, that third membership is inert -- titles+particles and
titles+particles+ambiguous parse byte-identically. Dropped, and control
3 now pins it, which makes the correction executable rather than prose.

test_properties.py carried the same borrow on a bigger surface: its
'Freiherr ' lead is one of four in a sweep over every ambiguous
particle, and if that lead goes transparent the _group shapes leave the
sweep while it keeps passing. Supplied there too.

  normal                                  2486 passed
  leading word out of titles+particles    only the cases.py tripwire
  chained words -> never-given            no test in this diff
  emitter suppressed                      8 failed (still sensitive)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@derek73
derek73 merged commit 715de3d into master Aug 15, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant