Skip to content

Track B G/R2: decide the open readings (stacked on #563) - #565

Draft
MaxGhenis wants to merge 13 commits into
masterfrom
trackb-readings-g-r2-20261023
Draft

MaxGhenis wants to merge 13 commits into
masterfrom
trackb-readings-g-r2-20261023

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Draft against master. #563 merged as edba88f, so this PR now targets master.

This PR finishes the work that #564 started for R3. It re-decides every remaining "Needs Max's judgment" item in the G and R2 design notes, plus #563's new refusals, under Max's 2026-10-20 delegation. Single readings are the session's call under P1–P4, logged in the source-conflict rulings with the ids below. Patterns and collisions between principles go to Max; one is queued as d1920, for 20 CFR versus POMS.

Readings that change money

Each reading keeps its rejected alternatives pinned as diagnostics and is checked by a Hypothesis property. Each has killed mutants (see below).

Id Before Now Basis
us:oasdi-dual-entitlement-zero-after-age-reduction Refused (parisi_redistribution_ambiguous) The spouse's age reduction stays in PTAP, and only the amount withheld for dual entitlement is redistributed: children $114.50 each, total $729 402(k)(3)(A) offsets "after any reduction under subsection (q)". 20 CFR 404.403(a)(5) excludes only "any amount not paid because of that person's entitlement on another earnings record (see § 404.407)". GN 02603.060 B.2's accounting agrees. A.2's disregard still applies when dual entitlement alone zeroes the rate (A.5, A.8, A.9)
us:oasdi-parent-entitlement-count-interval Refused for an own RIB between the 75% and 82.5% OBs The entitled set satisfies 402(h)(1)(D) for every parent at once, tested against the unrounded 82.5% and 75% of the PIA. One parent in the band: the other parent alone is paid $825. Two parents in the band: still refused 402(h)(1)(D) tests the RIB at 82.5% "if the amount of the parent's insurance benefit for such month is determinable under paragraph (2)(A) (or 75 percent ... in any other case)" (P1)
us:oasdi-dwb-1984-pre-1978-history Refused for cohorts that could have been entitled before 1978 Every month from January 1984 in a year before the cohort can attain 60 pays .715 of the unreduced WIB ($715). From 60 on, the row is still refused RS 00615.301B.1.e ("all disabled widow(er)s under age 60 receive .715 ... for 1/84 and later") and .310B.3 (the 1/84 recalculation), as specific rules over .005C.2's general one
us:oasdi-ret-grace-simultaneous-rib-dib Default excluded NSMs during technical DIB entitlement Default counts NSMs in months RIB is paid. Invented case: $4,200 paid rather than withheld. The CFR technical-entitlement exclusion stays selectable 42 U.S.C. 402(k)(4): "entitled to only the larger ... or, if such individual so elects, ... only the smaller of such benefits for such month" (P1). 20 CFR 404.407(c) says the same
us:oasdi-ret-deemed-entitlement-basis (a) Unmarried deemed recipient refused InvalidFamilyInput: the recipient is not on this NH's ledger and keeps $200 on their own record Act 203(b)(1) and 20 CFR 404.420 both require marriage, and RS 02501.140's wording yields to them (P1)
us:oasdi-ret-own-work-age-exemptions The own_work_exempt_months assertion was an optional broader reading Any non-empty value is InvalidFamilyInput. The Act exempts only CDB and DWB months, which the ledger already exempts by type 402(s)(3) and 402(e)(1)'s termination month

Refusals or defaults kept, with a stated basis

  • us:oasdi-saving-clause-procedure-gaps (new markers): RS 00630.400 (d1338) doesn't cover these configurations, so they stay refused. The sources are silent.
  • us:oasdi-dual-entitlement-pre-1978-history: stays refused. RS 00615.250 cites a .005F that doesn't exist.
  • us:oasdi-nh-charge-age-reduction-interaction: stays refused. No rule or example settles it.
  • us:oasdi-reduction-exact-fractions: not a conflict. The Act states fractions, and RS 00615.005B says "only fractions can be used".
  • us:oasdi-disability-family-maximum-rounding: floor to the dime. Under P1, the agency's published reading fills the statute's silence. A blind adjudication preferred leaving it unrounded; that view is recorded, and the stakes are at most $0.10 per auxiliary.
  • us:oasdi-ret-negative-nese-proration: floor, a close call. 203(f)(3) delegates the rounding to SSA, and RS 02501.080 uses "round down" to mean "to the next lower dollar". A blind adjudication preferred dropping the cents; that view is recorded.
  • us:oasdi-ret-deemed-entitlement-basis (b): a married ordinary adult child is entitled only through 402(d)(5) for a marriage made while disabled (402(s)(2)). That residual case stays refused.
  • us:oasdi-ret-other-deductee-scope: not a conflict. 20 CFR 404.441 governs.
  • Track B G part 2 and R2 part (b): deductions before reduction; SSA's operational saving clause #563's own readings: d1338 and its two logged rulings are re-framed in the note text only.

Sources and tests

  • New statutory text. 42 U.S.C. 402(d)(1)(D), (d)(5), (e)(1), (h)(1)(D), (h)(2), (k)(3)(A), (k)(4) and (s) were added to lii_usc_402_415_excerpts.txt. They come from a re-fetch whose body matched the pinned 402 SHA-256 byte for byte; the manifest's bytes, SHA-256 and note are updated.

  • tests/test_track_b_readings_20261023.py. It checks:

    • that the marker ids in the Track B package and the logged readings match both ways, sit in the G, R2, R3 or grace module, and appear as whole ids in a design note;
    • that no reading id and no "source conflict" text sits outside a marker;
    • that no G, R2 or R3 note opens a heading, paragraph, list item, table row or other block with "Needs Max's judgment";
    • that the new statutory quotes appear verbatim in the capture, once its whitespace runs read as single spaces.

    The G note states the exact rules.

  • Conformance report. It is regenerated: the 356,400-cell lattice is unchanged, and only the parent_benefit witness moves to two parents in the band.

  • Hypothesis properties:

    • test_method_b_counted_amount_is_the_before_age_amount: continuity, the A.2 boundary, and children never falling as the own benefit rises.
    • test_parent_entitlement_satisfies_402h1d_for_every_parent: an exact differential against a brute-force enumeration of the consistent sets.
    • test_historical_dwb_is_settled_exactly_before_the_cohort_can_attain_60: equals a post-1977 cohort exactly.
    • The grace properties: both readings over arbitrary months.

Blind adjudications (round 2)

Four Opus adjudications ran on a clean master clone without this PR's conclusions; they are in the evidence folder. They agreed on the parent count, the 1984 DWB rule, the RIB/DIB grace months, deemed entitlement, the kept refusals and R3. Their disagreements:

  • G2: $114.50, which I adopted. I had moved to $115.30 between rounds and reverted.
  • Disability-maximum rounding: unrounded. I kept the floor and recorded their view.
  • NESE: drop the cents. I kept the floor and recorded their view.

They also surfaced three findings, all applied: the unrounded parent thresholds, the unlawful own-work override, and the method-B figure for historical dual entitlement. Their 20 CFR-versus-Act instances are noted on Max's pattern decision d1920.

Mutation checks

Each check ran in an isolated copy of src/, with its import path verified. Each mutant failed at least one targeted test:

Mutant Result
Restore the zero-after-age refusal killed
Count only the $19.30 before-age amount killed
Disregard the spouse (A.2 after age reduction) killed
Use dime-floored parent thresholds killed
Allow the own-work override killed
No parent exclusion (count two) killed
Test the excluded parent at the paid rate killed
Refuse one in-band parent killed
Drop the 1984 DWB rule killed
Off-by-one on the age-60 year killed
CFR default for grace killed
Drop the marriage check killed

Verification so far

At head 479c321, the full Track B suite plus tests/ss passes: 12,581 passed, 6 skipped (pytest -n 4, with the staged-data roots unset). Black and ruff are clean on the changed files. The conformance report regenerates with only the parent witness changed.

Since then:

Still open: the round-9 review, CI at d636d76, then a tier slot. The coordinator's #563 comment names #574 next, so this PR may need one more master merge and recount.

axiom: n/a: microcosm-dynamics statutory reference, not a PolicyEngine country model.

🤖 Generated with Claude Code

Money-changing readings (each pinned with its rejected alternatives,
Hypothesis properties and killed mutants):
- us:oasdi-dual-entitlement-zero-after-age-reduction: count GN 02603.045's
  before-age amount (GN .050A ties exceptions 2-3 to .045); children
  $115.30 each instead of a refusal.
- us:oasdi-parent-entitlement-count-interval: the entitled set must satisfy
  402(h)(1)(D) for every parent; one in-band parent yields to the other at
  82.5 percent ($825); two in-band parents stay refused.
- us:oasdi-dwb-1984-pre-1978-history: RS 00615.301B.1.e pays .715 of the
  unreduced WIB in every pre-60 month from January 1984, whatever the
  entitlement date; from 60 the money history still refuses.
- us:oasdi-ret-grace-simultaneous-rib-dib: Act 202(k)(4) makes an elected
  RIB month entitlement to RIB alone, so the default now counts its NSMs.
- us:oasdi-ret-deemed-entitlement-basis: an unmarried deemed declaration is
  an input error (Act 203(b)(1), 20 CFR 404.420); the residual adult-child
  case stays refused.

Kept, with stated reasons and new markers: saving-clause procedure gaps,
historical dual entitlement, NH charges with age reductions (sources
silent); exact fractions, disability-maximum rounding, NESE floor,
own-work age exemptions, other-deductee scope (no conflict once the Act is
read whole). Notes re-framed; 402(d), (e), (h), (k), (s) excerpts added
from the pinned LII body; new tests/test_track_b_readings_20261023.py
checks markers against logged ids in both directions.

Stacked on #563; retarget to master after it merges.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
social-security-model Ready Ready Preview Nov 2, 2026 9:43pm UTC

Request Review

Four blind Opus adjudications (run on a clean master clone, without this
pass's conclusions) agreed on the parent count, the 1984 DWB rule, the
simultaneous RIB/DIB grace months, the deemed-entitlement marriage basis
and every kept refusal. Changes from their disagreements and findings:

- us:oasdi-dual-entitlement-zero-after-age-reduction: children $114.50,
  not $115.30. In 402(k)(3)(A)'s order the offset withholds $62.40 and age
  $20.90; 20 CFR 404.403(a)(5) excludes only the former (see 404.407(a))
  and GN 02603.060 B.2 keeps the age slice in PTAP. A.2's disregard stays
  for zeros that dual entitlement alone makes.
- us:oasdi-parent-entitlement-count-interval: test own RIBs against the
  unrounded 82.5 and 75 percent of the PIA that 402(h)(1)(D) names.
- us:oasdi-ret-own-work-age-exemptions: a non-empty own_work_exempt_months
  is now an input error; the Act exempts only CDB and DWB months.
- Historical dual entitlement: the method-B alternative ($96.50) is pinned
  beside method C's $99.30.
- Disability-maximum rounding and NESE floor are kept; the contrary blind
  views and their dime/dollar stakes are recorded in the notes.

Thirteen mutants (three per G2, four per parents, two per DWB, one each
for the grace default, the override and the marriage check) fail the new
tests in isolated copies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…/DIB elections

GPT-6.1 Sol r1 requested changes on 479c321 (no supported-dollar
regression found):
- tier counts: +19 unit tests (18 from the readings pass, one new invalid
  GraceMonth case below); unit 18,648, total 25,179, verified by
  collection;
- the G parent overview now states 402(h)(1)(D)'s unrounded thresholds;
- the R2 marriage passage and the RETBeneficiary docstring quote
  402(d)(1)(D)'s "month preceding" and 402(s)(2)'s third-prior-month
  clause;
- the disability-maximum note gives a real multi-COLA gap ($0.20), not a
  $0.10 bound; the NESE rationale states both meanings of "drop the
  cents"; the grace differential's labels name the new default;
- GraceMonth rejects RIB and DIB both received in one month (402(k)(4)).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sol r2 confirmed six of seven round-1 fixes; the remaining medium was the
R2 note's summaries of 402(s)(2). The table and the follow-on sentence now
say disability in the marriage month or in the third month before it, with
recovery before or after the marriage, matching the quoted statute; the
RETBeneficiary docstring says the same. Docs only; no code path changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolves the conflicts with #563's new row helper and relocated NH charge
refusal. _original_entitlement_rows now takes the payment month and the
resolved (count, excluded) parent set, and a _parent_threshold helper gives
each parent its 402(h)(1)(D) rate in G and in R2's context check (which
#563 added with the old parent_ob argument). The NH-age marker moves to
the relocated reserve check, and the G note adopts #563's framing of it
as deferred coverage, not a conflict. The marker test now requires every
marker to be documented in a Track B design note rather than matching
this pass's fixed set, since #563 logs its own readings. Tier counts:
unit 22,089, total 28,659.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#563's new head merges master into 434a39c with no Track B source change.
Only the tier files conflicted. Unit 22,879 (#563's 22,859 + 20), total
29,478.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Ready for hub review

This is an independent round-4 review (merge delta only) by a Claude Opus 5.5 cloud session, done for the Track B readings session.

Verdict: APPROVE at head 1fa568677983c6db3e4c9e80eb3018875ff88e22. The PR head on GitHub is still this SHA, and #563's head is still 03530e8bd99db9608ecfb60ae4f17508fde1b3be (git ls-remote, and gh api repos/PolicyEngine/microcosm-dynamics/pulls/565 gives .head.sha = 1fa56856…, base trackb-g2-r2b-20261023 @ 03530e8b…).

The merges carry the approved effect onto #563's new code. Every money and refusal decision I tested matches. I found four low or nit items, none of medium severity. Two are stale or weak documentation-integrity checks introduced by the merge. Two are pre-existing #563 behaviors that the brief's claims describe inaccurately. The merge carried both of those faithfully.

Findings

1. Low: the G note still says the readings test checks both directions

  • Where: docs/design/track_b_g_gross_benefits.md:3277-3281.
  • Problem: The note says "Every # Source conflict marker in the Track B modules names an id logged in the rulings, and every logged id has a marker: tests/test_track_b_readings_20261023.py checks both directions". Merge 1 replaced the exact-set test with test_each_reading_of_this_pass_has_a_marker_in_its_module (tests/test_track_b_readings_20261023.py:64) and test_every_marker_names_a_reading_documented_in_a_design_note (:76). Two markers in gross_benefits.py now name ids that are not in this pass's rulings table: us:oasdi-finality-protected-rates-before-coverage and us:oasdi-sole-full-deduction-zero-dual-composition. So the note's first clause is false at the head, and the test no longer checks it.
  • Evidence: grep -rn "# Source conflict" src/ | sed 's/.*# Source conflict //' | sort | uniq -c lists 20 ids. The rulings table at :3260-3272 and the test's READINGS (18 ids) don't contain those two.
  • Fix: Reword to: "every reading of this pass has a marker in a G, R2 or R3 module, and every marker names an id documented in some docs/design/track_b_*.md note."

2. Low: the reverse marker test uses a substring match, so a truncated or stale id passes

  • Where: tests/test_track_b_readings_20261023.py:76-83. The assertion is assert name in notes, where notes is all track_b_*.md text joined.

  • Counterexample (executed): I appended a marker line to src/populace_dynamics/track_b/ret_grace.py, ran the file, then ran git checkout -- <file> (status clean after).

    marker us:oasdi-made-up-reading:   1 failed, 14 passed
    marker us:oasdi-parent-entitlement: 15 passed   # truncation of us:oasdi-parent-entitlement-count-interval
    marker us:oasdi-ret-grace:          15 passed   # truncation of us:oasdi-ret-grace-simultaneous-rib-dib
    
  • What it still catches: a marker whose id appears nowhere in any Track B note.

  • What it misses: a truncated or typo'd id that is a prefix of a documented id. It also misses a stale marker whose id is still mentioned anywhere in a note, for example in a history paragraph or a superseded ruling. The old exact-set test caught both cases for G/R2/R3.

  • Fix: Compare whole ids, for example documented = set(re.findall(r"us:oasdi-[a-z0-9-]+", notes)), then assert name in documented. To keep the old strength, also assert set(markers) <= set().union(*READINGS.values()) | LATER_ROUND_READINGS, with the two Track B G part 2 and R2 part (b): deductions before reduction; SSA's operational saving clause #563 ids listed explicitly.

3. Low (pre-existing in #563, not introduced by this merge): R2's parent branch can't be reached, and no repo test pins its new threshold

  • Where: src/populace_dynamics/track_b/ret_ledger.py:1283-1326.
  • Problem: RecordYear.__post_init__'s role_types (ret_ledger.py:615-624) has no Role.PARENT entry, so any G context with a parent raises "G and RET benefit types differ".
  • Evidence (executed, scratch script probe.py): I constructed a RecordYear with one Role.PARENT context member, once for every BenefitType. All nine raise InvalidFamilyInput G and RET benefit types differ.
  • Consequence: the merge-adapted g._parent_threshold(state.pia, parents, auxiliary.beneficiary_id) call is unreachable through apply_ret_year. Mutations m4 and m5 below survive the whole Track B test set, and only my differential property (which bypasses __post_init__) kills them.
  • Severity: no public dollar amount or refusal can change, so I rate this low.
  • Fix (either one, Track B G part 2 and R2 part (b): deductions before reduction; SSA's operational saving clause #563's call):
    • Add a test that calls r._check_settled_family_facts on a parent context. My property below would do.
    • Or document that parents are outside R2 and drop the branch.

4. Nit: the NH-reservation × age-reduction refusal doesn't fire on the same inputs as at 4f1f70a2, but the change is #563's and the merge kept it intact

Checked and sound

Merge 2 claims (both verified).

  • Lines in the merge-2 result that differ from both parents (comm -12 of git diff --name-only 98c8b7e8 1fa56856 and git diff --name-only 03530e8b 1fa56856): only tests/README-tiers.md and tests/tier_counts.json.
  • git diff --stat 98c8b7e8 1fa56856 -- src/populace_dynamics/track_b docs/design 'tests/test_track_b*' is empty, so no Track B source, note or test changed in merge 2.
  • diff <(git diff 434a39c6 98c8b7e8) <(git diff 03530e8b 1fa56856) differs only in the two tier files' index lines and counts.

Approved diff vs current diff.

  • git diff --name-only f3b9a719 4f1f70a2 and git diff --name-only 03530e8b 1fa56856 list the same 22 files.
  • I compared the +/- lines of each file across the two diffs. Sixteen are identical. Six differ:
    • gross_benefits.py, ret_ledger.py, the G note and test_track_b_readings_20261023.py: each difference is one of the brief's adaptations 1-5. I read every differing line with diff <(git diff -U0 A B -- f) <(git diff -U0 C D -- f).
    • README-tiers.md and tier_counts.json: adaptation 6.
  • No difference outside the listed adaptations.

Adaptation 1 (gross_benefits.py).

  • _parent_threshold (:3869-3882) returns the 75% rate when parent_count == 2 or the id is excluded, and 82.5% otherwise. Both are unrounded, from _parent_entitlement_thresholds (:3864-3866). This matches the approved inline logic exactly.
  • _original_entitlement_rows (:4127-4173) passes parents[0] to the OB and _parent_threshold(...) to _is_entitled, and sets dwb_under_60 (:4170).
  • _family_benefits passes the whole-roster parents (:4253, :4264-4270).
  • The DRC caller (:4106-4117) passes the whole-roster _entitled_parent_count(state, beneficiaries, params) for a parent, and (1, frozenset()) otherwise.
  • Executed (scratch script drc_row.py): PIA $1,000, parent p with no own benefit, parent q with own RIB $800. The roster set is (1, frozenset({'q'})). q's one-member row with the roster set gives entitled False, OB 0, the same as its full-roster row. With parents=None it gives entitled True, OB 825. So the one-member row applies the two-parent rate to an excluded parent.

Adaptation 2 (R2 check): differential property, 3,000 examples, passed. The code is below. It generates:

  • PIA on dimes from $100.00 to $3,000.00;
  • one or two parents, each with no own benefit, or an own RIB at floor_dime(82.5%), floor_dime(75%) or 37.5% of the PIA, each ± up to $3.00 in dimes.

For each example it computes G's rows. It builds a one-month DECEASED RecordYear with every parent declared entitled and original_rates set to G's OB. It swaps the parent context in past __post_init__ (see finding 3), then calls r._check_settled_family_facts. Each example must:

  • be accepted when every G row is entitled;
  • be rejected with "auxiliary entitlement facts differ" otherwise;
  • have G's rows agree with a hand-written 402(h)(1)(D) oracle (mba < (75% if count == 2 or excluded else 82.5%)).

Results: STATS {'accept': 2019, 'reject': 786, 'skip': 195, 'excluded': 335, 'two': 733}, 2 passed. Skips are G's own two-in-band parent_benefit refusals.

offset = st.integers(-30, 30).map(lambda k: F(k, 10))

@settings(max_examples=3000, deadline=None)
@given(pia_dimes=st.integers(1000, 30000), n=st.sampled_from((1, 2)),
       anchors=st.lists(st.sampled_from(("one", "two", "none", "low")), min_size=2, max_size=2),
       offsets=st.lists(offset, min_size=2, max_size=2))
def test_r2_parent_check_matches_g_rows(pia_dimes, n, anchors, offsets):
    pia = F(pia_dimes, 10)
    one, two = g._parent_entitlement_thresholds(pia)
    members = []
    for i in range(n):
        base = {"one": one, "two": two, "low": two / 2, "none": None}[anchors[i]]
        own = None if base is None else max(F(0), g.floor_dime(base) + offsets[i])
        members.append(_parent("pq"[i], own))          # Role.PARENT, OLD_AGE own RIB, cohort 1950
    members = tuple(members)
    state = _state(pia)                                 # SURVIVOR, max 150%, elig 1990, no DRC clause
    try:
        count, excluded = g._entitled_parent_count(state, members, PARAMS)
    except g.FamilyConfigurationUnsupported:
        return
    rows = g._original_entitlement_rows(state, members, PARAMS, MONTH)   # 2024-01
    ob = g._original_benefit_validated(g.Role.PARENT, g.FamilyKind.SURVIVOR, pia, None, parent_count=count)
    record = _record(state, members, {m.beneficiary_id: ob for m in members})
    # _record: valid MOTHER_FATHER record, then object.__setattr__(record, "family_months", {1: parent context})
    if all(row.entitled for row in rows):
        r._check_settled_family_facts(record)
    else:
        with pytest.raises(g.InvalidFamilyInput, match="auxiliary entitlement facts differ"):
            r._check_settled_family_facts(record)
    for m, row in zip(members, rows):
        if m.own_benefit is None:
            assert row.entitled; continue
        mba = g._own_monthly_benefit_validated(m.own_benefit, PARAMS)[1]
        rate = two if (count == 2 or m.beneficiary_id in excluded) else one
        assert row.entitled is (mba < rate)

Adaptation 3 (NH refusal). The marker sits on the refusal line (gross_benefits.py:4931-4932), and the G note paragraph uses #563's "deferred coverage" framing. On the four inputs above, the decision equals #563's base. The scope differs from 4f1f70a2; see finding 4.

Adaptation 4 (notes and docstring).

Adaptation 5. See finding 2. The forward test still requires every one of this pass's 18 ids to have a marker in gross_benefits.py, ret_ledger.py, ret_grace.py or arf.py.

Adaptation 6 (tier counts). tests/tier_counts.json has unit 22,879 (base 22,859 + 20), and 22,879 + 4,271 + 1,471 + 520 + 337 = 29,478. README-tiers.md:42,47 agree. Running pytest --collect-only -q -m <tier> | tail -1 at the head gives:

unit: 22879/29478   artifact: 4271/29478   integration_psid: 1471/29478
reproduction_legacy: 520/29478   oracle_policyengine: 337/29478

Tests (Python 3.13.18, fresh venv, pip install -e ".[dev]", env vars as briefed).

  • The briefed 7 files: 402 passed in 43.32s.
  • The extended mutation set: the 7 files plus test_track_b_gross_benefits_parisi.py, test_track_b_ret_ledger_fix_round_6.py, test_track_b_ret_ledger_fix_round_5.py, test_track_b_gross_benefits_fix_round_13_guard.py, test_track_b_gross_benefits_savings_fix_round_2.py, test_track_b_gross_benefits_fix_round_1.py, test_track_b_gross_benefits_fix_round_2_history.py and test_track_b_gross_benefits.py. Baseline 1393 passed, and the property file 2 passed.

Mutations. Each was applied by exact single-match replacement, run with -x, then reverted with git checkout -- src/. git status --porcelain was empty after each one.

# Mutation Repo tests Property Outcome
m1 _parent_threshold: drop or beneficiary_id in excluded 1 failed 1 failed killed
m2 DRC caller passes None instead of parents 1393 passed 2 passed survived, equivalent (see below)
m3 drop dwb_under_60= in _original_entitlement_rows 1 failed passed killed
m4 (mine) R2: always the one-parent 82.5% rate 1393 passed 1 failed killed only by the property (finding 3)
m5 (mine) R2: pass (parents[0], frozenset()), dropping exclusions 1393 passed 1 failed killed only by the property (finding 3)
m6 (mine) _original_entitlement_rows: parent OB count fixed at 1 1 failed passed killed
m7 (mine) disable the NH × age-reduction refusal 1 failed passed killed

m2 is an equivalent mutant for _declared_widow_drc_protection_possible's boolean, although it does change the row (see adaptation 1). A parent is excluded only when another potential parent is entitled at the one-parent rate (gross_benefits.py:3913-3945). That other parent is subject (parents are not in _OUTSIDE_MAXIMUM, :1630), so it is counted either way. possible_widow comes only from widow roles, so the excluded parent's row can't change possible_count > 1 and possible_widow. The roster-level _entitled_parent_count call runs before the row in both versions, so refusals are identical. The fix is correct but unobservable here.

Style. black -l 79 --check on the two modules and the test file: "3 files would be left unchanged". ruff check on the same: "All checks passed!".

Protected files. git diff --name-only 03530e8b 1fa56856 | grep -E 'gates.yaml|engine/loop.py|engine/steps.py|^runs/' returns nothing.

CI at the head:

pytest (3.14) success; pytest-shard 1/4-4/4 (3.14) success; graph-integration (3.13), (3.14) success;
lint success; build success; Vercel Preview Comments success; deploy skipped

What I couldn't check

  • I didn't run the full suite locally. CI's green run is the evidence for everything outside the 15 files above, and for test_tier_policy.py, which needs the whole session collected. Run alone it sees one test and fails by design. I checked its manifest with --collect-only per tier instead.
  • I didn't re-review the readings themselves, per the brief. Nor did I review Track B G part 2 and R2 part (b): deductions before reduction; SSA's operational saving clause #563's own changes (rounds 2-10 and the master merges) except where they meet this PR's lines.
  • Finding 4's B and C dollar results are Track B G part 2 and R2 part (b): deductions before reduction; SSA's operational saving clause #563's behavior. I didn't check them against sources.
  • No PSID, EPUF or PolicyEngine-US data was available, and none was needed.
  • The differential property bypasses RecordYear.__post_init__, because no public input reaches the parent branch (finding 3). It therefore checks the branch's logic, not a supported public path.

Generated by Claude Code

The cloud round-4 review (APPROVE at 1fa5686) found two low items in
this PR's bookkeeping:

- The reverse marker test matched substrings, so a truncated or
  misspelled id passed when it was a prefix of a documented id. It now
  extracts whole ids from the Track B notes.
- The G note still said the test checks markers against the logged ids
  in both directions. The test now does so again: the markers in the G,
  R2, R3 and grace modules must equal this pass's readings plus the ids
  other rounds register (#563's two), and the note says what it checks.

The insured-status modules keep their own register, as in the round-3
test, so #562's markers don't enter these checks once it lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Ready for hub review

This is an independent round-5 review (fix delta) by a Claude Opus 5.5 cloud session, written for the Track B readings session.

Verdict: REQUEST_CHANGES at e75328f485e49d0e7c63bbca31ad8fdff0ab1261 (the PR head on GitHub at review time).

Findings 1 and 2 from round 4 are mostly resolved. A prefix truncation now fails both tests. The note no longer claims the old two-way check. Two medium gaps remain, and both follow from the same thing: the note and docstring say "every marker", but the test sees only markers in the exact one-line # Source conflict us:oasdi-<id> form outside the insured-status files.

Findings

1. Medium: a # Source conflict marker the regex can't parse passes silently in the G, R2, R3 and grace modules

tests/test_track_b_readings_20261023.py:63 (MARKER) and :66-75 (_module_markers). MARKER needs # Source conflict followed directly by the id on the same line. Any other form is invisible to both tests: an id wrapped onto the next line, or a colon after "conflict". The wrapped form already occurs in #562: insured_status.py:1338-1339 and :2534-2535 at 168bb3a8 write # Source conflict and then # us:oasdi-insured-subsequent-special-long-period on the next line. A new, undocumented reading written that way in ret_grace.py passes. The note (docs/design/track_b_g_gross_benefits.md:3279-3282) says it can't.

Counterexamples (executed at the head, each restored afterwards with git checkout e75328f4 -- <file>):

$ printf '# Source conflict\n# us:oasdi-brand-new-undocumented\n' >> src/populace_dynamics/track_b/ret_grace.py
$ python -m pytest -p no:cacheprovider -q tests/test_track_b_readings_20261023.py -k "both_directions or documented_in"
2 passed, 13 deselected
$ echo "# Source conflict: us:oasdi-brand-new-undocumented" >> src/populace_dynamics/track_b/ret_grace.py
  (same command)
2 passed, 13 deselected

Fix: in each module outside OWN_REGISTERS, require every "Source conflict" occurrence to parse as a marker. Combine this with the lookahead in finding 3. I applied this locally and checked it: the head passes 15/15, and all four counterexamples in findings 1 and 3 then fail both tests.

MARKER = re.compile(rf"# Source conflict ({ID})(?=:|\s|$)")
...
    for path in sorted(MODULES.glob("*.py")):
        text = path.read_text()
        if path.name not in OWN_REGISTERS:
            assert text.count("Source conflict") == len(
                MARKER.findall(text)
            ), path.name
        for match in MARKER.finditer(text):

2. Medium: the note and docstring say "every marker" is documented, but the test exempts the insured-status files, and #562 brings in six undocumented insured ids

The note is docs/design/track_b_g_gross_benefits.md:3281-3282 ("every marker must name a whole id that a Track B design note documents"). The docstring is tests/test_track_b_readings_20261023.py:6-7. The exemption is at :60-61 and :71-75. Neither the note nor the docstring mentions the exemption. The comment at :60 says "Insured-status modules keep their own register of readings", but #562 has no register of this kind for most of its ids. On a scratch merge of 168bb3a8 into e75328f4, I listed the markers the test can see in the two exempt files and compared them with every whole id in docs/design/track_b_*.md:

insured_status.py visible markers: 8 undocumented: ['us:oasdi-insured-flag-first-insured-quarter', 'us:oasdi-insured-historical-end-recovery-month', 'us:oasdi-insured-pre1951-seven-elapsed-years', 'us:oasdi-insured-prior-disability-favorable-disregard', 'us:oasdi-insured-unknown-prior-historical-blindness']
_insured_status_qc.py visible markers: 1 undocumented: ['us:oasdi-insured-disability-period-endpoint-quarters']

git grep -F <id> 168bb3a8 -- docs tests returns nothing for any of those six ids. Once #562 lands, the note's sentence becomes false while the test stays green. I'm not saying the exemption is wrong: it is what keeps this test from failing on #562. The problem is that the note and docstring describe a stricter check than the one the test runs.

Fix: say "every marker outside the insured-status modules (insured_status.py, _insured_status_qc.py), which this test exempts" in both the note and the docstring. Change the comment at :60 to what the code does, for example "exempt: #562's insured-status readings are not all logged in a Track B note yet". If the insured ids are meant to be documented somewhere, that belongs on #562.

3. Low: a misspelling that extends a documented id past a non-id character still passes

tests/test_track_b_readings_20261023.py:62-63. The id pattern stops at the first character outside [a-z0-9-], and MARKER has no right boundary. A marker such as us:oasdi-parent-entitlement-count-intervalX or ...-interval_v2 therefore reads as the documented id. Round 4's finding 2 was about prefixes, and those now fail. This case is the mirror image.

$ echo "# Source conflict us:oasdi-parent-entitlement-count-intervalX" >> src/populace_dynamics/track_b/ret_grace.py
$ python -m pytest ... -k "both_directions or documented_in"
2 passed, 13 deselected
$ echo "# Source conflict us:oasdi-parent-entitlement-count-interval_v2" >> src/populace_dynamics/track_b/ret_grace.py
2 passed, 13 deselected

Fix: add the lookahead (?=:|\s|$) to MARKER (shown under finding 1). The existing markers end in a newline or : (gross_benefits.py:2772, :4987, :5833), and they all still parse.

4. Nit: the note leaves out one check the test makes

docs/design/track_b_g_gross_benefits.md:3278-3284 lists the marker checks, the judgment-heading check and the verbatim-quote check. It does not say that test_each_note_names_its_readings_and_has_no_open_judgment_heading (tests/test_track_b_readings_20261023.py:100-105) also requires each note to contain its own READINGS ids. Add "and must name each of its readings" to the heading sentence.

Checked and sound

  • Head and CI. git rev-parse HEAD gives e75328f485e49d0e7c63bbca31ad8fdff0ab1261, and the REST PR head is the same. The commit's parent is 1fa56867. git diff --stat 1fa56867 e75328f4 touches only tests/test_track_b_readings_20261023.py (+28/−14) and the G note (+11/−8).

  • Test run. Python 3.13.18 with a fresh .venv and pip install -e ".[dev]", using the brief's env vars. pytest -q tests/test_track_b_readings_20261023.py gives 15 passed, and --collect-only gives 15 tests collected. tests/tier_counts.json is unchanged between 1fa56867 and e75328f4 (empty git diff --stat), which is consistent with claim 5.

  • Style. black -l 79 --check reports "1 file would be left unchanged", and ruff check reports "All checks passed!".

  • Claim 1 (whole ids). Read at :62-63 and :91-97. The documented set is built with re.findall(ID, ...) across every docs/design/track_b_*.md, and membership is exact. grep -noE "us:oasdi-...-?$" over the notes finds no id cut by a line wrap, so no note contributes a truncated id to the documented set.

  • Claim 2 (exact set). Read at :54-59 and :78-88. set(markers) == logged, and each logged id must sit only in the four modules. Both OTHER_ROUNDS ids are at gross_benefits.py:1748 and :4987.

  • Claim 3 (exemption and Track B insured status: quarters of coverage; fully, currently and disability insured #562). I merged 168bb3a8 into a detached e75328f4 with --no-ff --no-commit. Only tests/README-tiers.md and tests/tier_counts.json conflicted, and I took ours for both. pytest tests/test_track_b_readings_20261023.py tests/test_track_b_insured_status_fix_round_15.py gives 63 passed. With 1fa56867's version of the readings test on the same merge I got 1 failed, 14 passed, and the failure was test_every_marker_names_a_reading_documented_in_a_design_note with AssertionError: us:oasdi-insured-disability-period-endpoint-quarters. I aborted the merge afterwards.

  • Exemption scope. It applies only when an id's files are a subset of OWN_REGISTERS (:74). An id that also appears in a G-side module is not exempt (mutation 10 below). It does not hide a misplaced G, R2 or R3 reading: moving one into an insured file alone drops it from markers, and the equality check fails. The two wrapped markers in Track B insured status: quarters of coverage; fully, currently and disability insured #562's insured_status.py are invisible to MARKER, but they are in exempt files, so the test loses nothing there. The same blind spot outside those files is finding 1.

  • Claim 4 (note wording). I read the new paragraph. The first sentence is now active, and the marker sentence matches the code apart from findings 2 and 4.

  • Mutations. Each one ran -k "both_directions or documented_in" at the head. I restored the files with git checkout e75328f4 -- <files> and checked git status was clean after each one.

    # Mutation Expected Result
    1 Append # Source conflict us:oasdi-parent-entitlement to ret_grace.py Both fail 2 failed
    2 Mutation 1, plus the truncated id in OTHER_ROUNDS Only the whole-id test fails 1 failed (documented), 1 passed
    3 Delete the grace module's only marker (ret_grace.py:461) Fail Equality test failed, 1 passed
    4 Drop us:oasdi-sole-full-deduction-zero-dual-composition from OTHER_ROUNDS Fail Equality test failed, 1 passed
    5 Undocumented marker in a new insured_status.py Both pass 2 passed
    6 (mine) The same undocumented id in both insured_status.py and ret_grace.py Both fail 2 failed
    7 (mine) Undocumented marker in a new track_b/extra.py Both fail 2 failed
    8 (mine) Truncate the grace marker by one segment (...-simultaneous-rib) Both fail 2 failed
    9-12 (mine) Wrapped id, conflict: colon form, ...intervalX, ...interval_v2 Should fail All passed: findings 1 and 3
  • CI. At review time lint, build, both graph-integration jobs and pytest-shard 3/4 had passed, and deploy was skipped. Shards 1/4, 2/4 and 4/4 were still in progress.

What I couldn't check


Generated by Claude Code

… stated

The cloud round-5 review requested changes on e75328f:

- A marker the regex couldn't parse (an id wrapped onto the next line,
  "conflict:" with a colon, lowercase) was invisible to both marker
  tests. Outside the exempt modules, every mention of a source conflict
  must now parse as a one-line marker.
- An id extended past a non-id character ("...intervalX", "..._v2") read
  as the documented id. A marker's id must now end at a colon,
  whitespace or the end of the file, and a note's id must not run on
  into another id character or hyphen.
- The note and docstring said "every marker" without the insured-status
  exemption. Both now state it and why: the source-conflict rulings log
  #562's insured-status readings, but no Track B note documents all of
  them yet. The note also says each note must name its own readings.

Sixteen mutations, including all twelve of the review's, behave as
expected; the file still collects 15 tests, so the tier counts don't
change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Ready for hub review

This is an independent round-6 review (fix delta) by a Claude Opus 5.5 cloud session, written for the Track B readings session.

Verdict: REQUEST_CHANGES at 0d186c7163e186cbb99417f7b3cc182ece43f76c (the PR head on GitHub at review time).

All four round-5 findings are resolved for the cases round 5 named, and all twelve round-5 mutations now behave as the note says. One medium gap remains. The new note says the test covers "every Track B module" and "every mention of a source conflict", but the parse rule misses two shapes: a hyphenated Source-conflict (the spelling the notes themselves use) and any module in a subpackage. Both let an undocumented marker pass. The fix is two characters of regex plus rglob, and I checked that it keeps the head and both scratch merges green.

Findings

1. Medium: the parse rule misses Source-conflict and the parameters/ subpackage, so an undocumented marker passes where the note says it can't

tests/test_track_b_readings_20261023.py:70 (MENTION) and :80 (MODULES.glob("*.py")). The note (docs/design/track_b_g_gross_benefits.md:3278-3283) says the test "pins the bookkeeping for every Track B module except the insured-status ones" and that "every mention of a source conflict must be a one-line # Source conflict <id> marker". The _module_markers docstring (:76-77) says "a wrapped, mistyped or reworded one fails". Two cases contradict this:

  • MENTION is source\s+conflict, so a hyphen or underscore between the words is not a mention. The G, R2 and R3 notes use "source-conflict" on 12 lines between them (git grep -c -i source-conflict HEAD -- docs/design: G 6, R2 5, R3 1), so this spelling is a likely slip in a code comment.
  • glob("*.py") is not recursive. src/populace_dynamics/track_b/parameters/__init__.py is a Track B module the test never reads.

Counterexamples (executed at the head; each file restored with git checkout 0d186c71 -- src tests docs, and git status --short was empty afterwards):

$ echo '# Source-conflict us:oasdi-brand-new-undocumented' >> src/populace_dynamics/track_b/ret_grace.py
$ python -m pytest -p no:cacheprovider -q tests/test_track_b_readings_20261023.py -k "both_directions or documented_in"
2 passed, 13 deselected
$ echo '# Source conflict us:oasdi-brand-new-undocumented' >> src/populace_dynamics/track_b/parameters/__init__.py
  (same command)
2 passed, 13 deselected

Fix:

MENTION = re.compile(r"source[\s_-]*conflict", re.IGNORECASE)
...
    for path in sorted(MODULES.rglob("*.py")):

I applied both changes locally and checked them. The head gives 15 passed, and each counterexample above then gives 2 failed. On the #562 scratch merge (168bb3a8) and the #563 scratch merge (dbdceac5), the patched test gives 15 passed. On both merges, a count with the widened pattern over rglob("*.py") equals the count with the current pattern in every file, so the wider pattern adds no new mention to any module there. The alternative is to narrow the note and docstring to the top-level modules and the spaced spelling, but that leaves the slip open.

2. Low: the note-names check uses substring matching, so a note can "name" a reading only through a typo

tests/test_track_b_readings_20261023.py:120-121 checks name in text. This commit made marker ids and documented ids whole, but this check still passes on a longer id. If the G note misspells a reading that another note also carries whole, every test stays green:

$ sed -i 's/us:oasdi-ret-temporary-partial-deduction/us:oasdi-ret-temporary-partial-deductionX/g' docs/design/track_b_g_gross_benefits.md
$ grep -c deductionX docs/design/track_b_g_gross_benefits.md
2
$ python -m pytest -p no:cacheprovider -q tests/test_track_b_readings_20261023.py
15 passed

The note says only that each note "must name each of their readings", so this is not a misstatement. It is the one id check in the file that still allows a suffix. Fix: assert name in DOCUMENTED.findall(text), (note, name).

3. Nit: the note doesn't state the marker's right boundary

The code comment at :66 says a marker id ends at a colon, whitespace or the end of the file. The note says only "one-line # Source conflict <id> marker". A marker followed by ., , or ) fails both tests (mutations 14, 15 and 23 below). That failure is loud and no existing marker trips it, so it is safe. The note could add "followed by a colon or a line break" so a writer knows why.

Round-5 findings

  1. Unparseable markers (medium): resolved for the two forms named (wrapped id, conflict:), plus lowercase, double space and prose mentions. Finding 1 above is the remaining part.
  2. Exemption unstated (medium): resolved. The note (:3278-3281), the docstring (:5) and the comment (:62-63) now name the exempt modules and say why. The exemption stays per id (:87-91).
  3. Suffix extension (low): resolved. MARKER has (?=:|\s|$) (:67), and the documented set uses (?[A-Za-z0-9_-]) (:69, :111).
  4. Note leaves out the readings check (nit): resolved. The note now says the notes "must name each of their readings" (:3286).

Checked and sound

  • Head. git rev-parse HEAD gives 0d186c7163e186cbb99417f7b3cc182ece43f76c, and gh api repos/.../pulls/565 --jq .head.sha gives the same. Its parent is e75328f4. git diff --stat e75328f4 0d186c71 touches only docs/design/track_b_g_gross_benefits.md (+9/−5) and tests/test_track_b_readings_20261023.py (+25/−9).

  • Test run. Python 3.13.18, fresh .venv, pip install -e ".[dev]", the brief's env vars. pytest -q tests/test_track_b_readings_20261023.py gives 15 passed, and --collect-only gives 15 tests collected. git diff --stat e75328f4 0d186c71 -- tests/tier_counts.json is empty.

  • Style. black -l 79 --check reports "1 file would be left unchanged", and ruff check reports "All checks passed!".

  • Existing markers. grep -rniE "source\s+conflict" over the non-exempt modules finds 25 mentions, all one-line markers ending in a newline or : (for example gross_benefits.py:2772, :4987, :5833). All of them parse, so the boundary and parse rule reject no current marker.

  • Scratch merges. I merged each PR into a detached 0d186c71 with --no-ff --no-commit. For Track B insured status: quarters of coverage; fully, currently and disability insured #562 (168bb3a8), only tests/README-tiers.md and tests/tier_counts.json conflicted, and I took ours for both. Track B G part 2 and R2 part (b): deductions before reduction; SSA's operational saving clause #563 (dbdceac5, 4 commits past the branch's base) merged without conflicts. The readings test gives 15 passed on each. I aborted both merges, and git status --short was empty afterwards. On the Track B insured status: quarters of coverage; fully, currently and disability insured #562 merge, the parse rule scans arf.py, gross_benefits.py, ret_grace.py and ret_ledger.py and skips the two exempt files, which carry 14 mentions between them.

  • Prose. Apart from finding 1, the rewritten note paragraph matches the code: the per-id exemption, the exact set (:94-97), the four allowed files (:98-104), the whole-id documentation check (:107-113) and the judgment-heading check (:119). The docstring (:5-10) says the same.

  • Mutations. Each ran -k "both_directions or documented_in" at the head unless noted. I restored with git checkout 0d186c71 -- src tests docs plus git clean for new files, and git status --short was empty after each.

    # Mutation Expected from the note Result
    1 Append truncated us:oasdi-parent-entitlement marker to ret_grace.py Both fail 2 failed
    2 Mutation 1, plus the truncated id in OTHER_ROUNDS Only the whole-id test fails 1 failed (documented), 1 passed
    3 Delete the grace marker (ret_grace.py:461) Exact-set test fails 1 failed (both_directions), 1 passed
    4 Drop us:oasdi-sole-full-deduction-zero-dual-composition from OTHER_ROUNDS Exact-set test fails 1 failed (both_directions), 1 passed
    5 Undocumented marker in a new insured_status.py Exempt: pass 2 passed
    6 Same undocumented id in insured_status.py and ret_grace.py Both fail 2 failed
    7 Undocumented marker in a new track_b/extra.py Both fail 2 failed
    8 Truncate the grace marker to ...-simultaneous-rib Both fail 2 failed
    9 Wrapped id (# Source conflict / # us:oasdi-...) in ret_grace.py Fail 2 failed
    10 # Source conflict: us:oasdi-... Fail 2 failed
    11 ...-count-intervalX Fail 2 failed
    12 ...-count-interval_v2 Fail 2 failed
    13 (mine) Prose "source conflict" in b2.py's module docstring Fail ("every mention") 2 failed
    14 (mine) Trailing . on the grace marker Fail (comment :66) 2 failed
    15 (mine) ) after the grace marker id Fail 2 failed
    16 (mine) Undocumented id in _insured_status_qc.py and in gross_benefits.py Not exempt: both fail 2 failed
    17 (mine) # Source-conflict us:oasdi-brand-new-undocumented in ret_grace.py Fail 2 passed (finding 1)
    18 (mine) Lowercase # source conflict us:oasdi-... Fail 2 failed
    19 (mine) Undocumented marker in track_b/parameters/__init__.py Fail 2 passed (finding 1)
    20 (mine) Wrapped marker in a new insured_status.py Exempt: pass 2 passed
    21 (mine) Wrap the grace id at a hyphen in every note Whole-id test fails 1 failed (documented), 1 passed
    22 (mine) Note typo ...-rib-dibX in every note Whole-id test fails 1 failed (documented), 1 passed
    23 (mine) , after the grace marker id Fail 2 failed
    24 (mine) Source conflict (two spaces) Fail 2 failed
    25 (mine) # See the source conflicts above. in ret_grace.py Fail ("every mention") 2 failed
    26 (mine) The marker text inside a string literal in ret_grace.py Parsed as a marker: fail 2 failed
    27 (mine, full file) G note misspells us:oasdi-ret-temporary-partial-deduction with a trailing X — 15 passed (finding 2)

What I couldn't check


Generated by Claude Code

The cloud round-6 review requested changes on 0d186c7:

- The parse rule missed a hyphenated "Source-conflict" (the spelling the
  notes use) and never read the parameters subpackage, so an
  undocumented marker passed there. Mentions now match any spelling
  (source[\W_]*conflict, any case), and the scan covers every Python and
  YAML file in the Track B package, subpackages included. Files are
  named by their path inside the package, so only the top-level
  insured-status modules are exempt.
- The check that each note names its readings matched substrings, so a
  note could name a reading only through a typo. It now uses whole ids.
- The note now states where a marker's id ends.

Thirty mutations behave as the note says, including all of rounds 5 and
6 plus YAML, subpackage, README and split-line cases. The file still
collects 15 tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A plural "# Sources conflict us:oasdi-..." still slipped past the parse
rule. The mention pattern is now sources?[\W_]*conflict (any case). On
this head, #562's 168bb3a and #563's dbdceac, every mention in a
non-exempt Python or YAML file still parses as a marker; the only
mismatch is #562's two wrapped markers in the exempt insured_status.py.
All 32 mutations behave as the note says.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Ready for hub review

This is an independent round-7 review (fix delta plus a full pass of the marker test) by a Claude Opus 5.5 cloud session, written for the Track B readings session.

Verdict: REQUEST_CHANGES at 079c33dae15c2a6693b3132e451567ecdcfd00fc (the PR head on GitHub at review time).

All three round-6 findings are resolved, and all 27 round-5 and round-6 mutations behave as the note says. The full pass found one medium gap and five smaller ones. The medium gap: the parse rule finds markers by the phrase "source conflict", not by the reading id. A marker worded any other way, such as # Conflicting sources us:oasdi-<id>, or a bare id in a comment, passes with an undocumented id. The _module_markers docstring says "a wrapped, mistyped or reworded one fails". One added assertion closes it: every us:oasdi occurrence in a scanned file must be a parsed marker. That holds today on the head and on both scratch merges. A combined patch for all six findings is at the end. I applied it and checked it against every mutation below and both merges.

Findings

1. Medium: a reworded marker or a bare id passes with an undocumented reading

tests/test_track_b_readings_20261023.py:72 (MENTION) and :90-91. The only parse check counts phrase matches (sources?[\W_]*conflict) against markers. An id in a comment that doesn't use that phrase is neither a mention nor a marker, so both tests ignore it. The docstring at :80-81 says "every mention of a source conflict must parse as a marker, so a wrapped, mistyped or reworded one fails". The note (docs/design/track_b_g_gross_benefits.md:3282-3284) says every mention "in any spelling" must be a marker. A reading logged as # Conflicting sources us:oasdi-<id> is a reworded mention, and it passes.

Counterexamples, executed at the head. Each one appended a line to ret_grace.py. I restored with git checkout 079c33da -- src tests docs and git clean -f, and git status --short was empty after each.

$ echo '# Conflicting sources us:oasdi-brand-new-undocumented' >> src/populace_dynamics/track_b/ret_grace.py
$ python -m pytest -p no:cacheprovider -q tests/test_track_b_readings_20261023.py -k "both_directions or documented_in"
2 passed, 13 deselected
# Conflict of sources: us:oasdi-brand-new-undocumented   -> 2 passed
# Sources in conflict us:oasdi-brand-new-undocumented    -> 2 passed
# Source dispute us:oasdi-brand-new-undocumented         -> 2 passed
# Reading us:oasdi-brand-new-undocumented                -> 2 passed

No list of spellings can cover every rewording. The id is the part that matters, and it has a fixed form. Fix: in each non-exempt file, also require the number of case-insensitive us:oasdi occurrences to equal the number of parsed markers:

ANY_ID = re.compile(r"us:oasdi", re.IGNORECASE)
...
        if name not in OWN_REGISTERS:
            assert len(MENTION.findall(text)) == len(ids), name
            assert len(ANY_ID.findall(text)) == len(ids), name

Today every us:oasdi occurrence in a non-exempt Python or YAML file sits on a marker line. I checked with git grep -n -i us:oasdi <tree> -- src/populace_dynamics/track_b | grep -v '# Source conflict us:oasdi' | grep -v insured_status, which printed nothing for 079c33da, 168bb3a8 and dbdceac5. On both scratch merges the per-file counts are equal: arf.py 5/5, gross_benefits.py 14/14, ret_grace.py 1/1, ret_ledger.py 5/5, and _insured_status_qc.py 1/1 on the #562 merge. With the check added, all five counterexamples give 2 failed. Add a sentence to the note and the docstring, for example "and every reading id in those files must sit in such a marker". Change "reworded" in the docstring to "or a reworded mention that carries an id".

2. Low: .YAML, .Yml and .pyi files are skipped

:74 (SOURCES) and :85. path.suffix is compared case-sensitively, and .pyi is not in the set. The note (:3278-3279) says the test covers "every Python and YAML file in the Track B package". The package has no such file today, so this only matters for a future file.

$ echo '# Source conflict us:oasdi-brand-new-undocumented' > src/populace_dynamics/track_b/parameters/ret_v2.YAML
  (same -k command) -> 2 passed
$ echo '# Source conflict us:oasdi-brand-new-undocumented' > src/populace_dynamics/track_b/ret_grace.pyi
  -> 2 passed

.json and .toml files also pass (2 passed), but the note doesn't claim those. Fix: path.suffix.lower() and add .pyi. Both counterexamples then give 2 failed. If you'd rather keep the set as it is, write ".py, .yaml and .yml files" in the note.

3. Low: the judgment-heading check misses common variants of the heading

:126. The regex is ^#+ Needs Max's judgment, case-sensitive, with a straight apostrophe and an ATX heading at column 0. The note (:3289) says each note must "carry no open 'Needs Max's judgment' heading". All three notes already use the curly apostrophe ’ elsewhere (grep -c "’": G 1, R2 3, R3 1). I appended each of these to the G note and ran the whole file:

Appended heading Result
## Needs Max’s judgment (curly apostrophe) 15 passed
## Needs Max's Judgment 15 passed
Setext Needs Max's judgment over ---- 15 passed
## Needs Max's judgment (two-space indent) 15 passed
## Needs Max's judgment (control) 1 failed, 14 passed

Fix (in the patch below): case-insensitive, either apostrophe, up to three leading spaces, and the setext form. It doesn't match the plain-prose lines that already start with "Needs Max's judgment items" (G note :1706, :1775). With it, all five rows fail, and the head and both merges pass.

4. Nit: MENTION has no left boundary, so it rejects "resource conflict"

:72. sources? matches inside "resource". Its [\W_]* also crosses sentence punctuation. Both cases make the test reject prose that isn't about a source conflict. Neither occurs in any of the three trees (git grep -i -E 'resources?[^a-z0-9]*conflict' printed nothing).

$ echo '# Lock to avoid a resource conflict.' >> src/populace_dynamics/track_b/runner.py      -> 2 failed
$ echo '# Read the source. Conflicts are logged in the G note.' >> .../runner.py           -> 2 failed

A reading id that contains source-conflict would count twice and fail, even when it is logged and documented. I renamed the grace reading to us:oasdi-ret-grace-source-conflict-rib-dib in the module, the test and the notes, and got 2 failed, 13 passed. A control rename to ...-other-rib-dib gave 15 passed. Fix: (?<[a-z]) before sources? closes the "resource" case. With finding 1 in place, the sentence-boundary case is just over-strict, and you can keep it. If you keep it, say so in the comment at :71.

5. Nit: DOCUMENTED has a right boundary but no left one

:70. An id counts as documented when it appears only as the tail of a longer token. I added the undocumented id to OTHER_ROUNDS and a marker to ret_grace.py. Writing See xus:oasdi-brand-new-undocumented. in the R2 note then gave 15 passed. The control without the note line gave 1 failed, 14 passed. Fix: (?<[A-Za-z0-9_-]) in front of {ID}. That gives 1 failed, 14 passed.

6. Nit: "verbatim" means verbatim after whitespace is collapsed

:161 joins the capture's whitespace runs into single spaces before it checks the quote. The note (:3290) says each passage "must appear verbatim in the capture". The collapse is needed, because the capture wraps lines. "verbatim up to whitespace" would match what the code does. No code change is needed.

Combined patch (applied and checked)

-DOCUMENTED = re.compile(rf"{ID}(?[A-Za-z0-9_-])")
+DOCUMENTED = re.compile(rf"(?<[A-Za-z0-9_-]){ID}(?[A-Za-z0-9_-])")
 #: Any spelling: "source conflict", "Source-conflict", "Sources conflict".
-MENTION = re.compile(r"sources?[\W_]*conflict", re.IGNORECASE)
+MENTION = re.compile(r"(?<[a-z])sources?[\W_]*conflict", re.IGNORECASE)
+#: Any reading id, in any case: each must sit in a marker.
+ANY_ID = re.compile(r"us:oasdi", re.IGNORECASE)
 #: Files that can carry a marker, subpackages included.
-SOURCES = {".py", ".yaml", ".yml"}
+SOURCES = {".py", ".pyi", ".yaml", ".yml"}
@@ def _module_markers():
-        if path.suffix not in SOURCES or not path.is_file():
+        if path.suffix.lower() not in SOURCES or not path.is_file():
@@
             assert len(MENTION.findall(text)) == len(ids), name
+            assert len(ANY_ID.findall(text)) == len(ids), name
@@ def test_each_note_names_its_readings_and_has_no_open_judgment_heading(note):
-    assert not re.search(r"^#+ Needs Max's judgment", text, re.MULTILINE)
+    assert not re.search(
+        r"^ {0,3}(#+ *needs\s+max['’]s\s+judge?ment"
+        r"|needs\s+max['’]s\s+judge?ment.*\n {0,3}(-+|=+) *$)",
+        text,
+        re.MULTILINE | re.IGNORECASE,
+    )

With this patch: the head gives 15 passed, and both scratch merges give 15 passed. black -l 79 --check reports "1 file would be left unchanged", and ruff check reports "All checks passed!". Every round-5 and round-6 mutation I reran keeps its outcome (R5-1 to 5 and 9, R6-17, 19, 20, 25 and 27). Every counterexample in findings 1-3 and 5 now fails, and so does the "resource conflict" line from finding 4. The note and docstring need the sentences named in findings 1, 2 and 6.

Round-6 findings

  1. Source-conflict and the parameters/ subpackage (medium): resolved. MENTION is sources?[\W_]*conflict, any case (:72). The scan is rglob("*") filtered to .py/.yaml/.yml files (:84-86). Files are named by their path inside the package (:87), so only the top-level insured_status.py and _insured_status_qc.py are exempt. Mutations R6-17 and R6-19 now give 2 failed. A marker in a new parameters/insured_status.py gives 2 failed, so it is not exempt. A logged id duplicated into parameters/ret_v1.yaml gives 1 failed, 1 passed (the location check). The remaining gaps are findings 1 and 2.
  2. Note-names check used substrings (low): resolved. :127-129 checks membership in DOCUMENTED.findall(text). R6-27 (G note ...deductionX) now gives 1 failed, 14 passed. The left-boundary nit is finding 5.
  3. Note didn't state the right boundary (nit): resolved. The note (:3284-3285) says the id "ends at a colon, whitespace, a line break or the end of the file", which matches (?=:|\s|$) at :68.

Checked and sound

  • Head. git rev-parse HEAD gives 079c33dae15c2a6693b3132e451567ecdcfd00fc, and gh api repos/.../pulls/565 --jq .head.sha gives the same. The commit's parent is db268f97, and that commit's parent is 0d186c71. git diff --stat 0d186c71 079c33da touches only the G note (+13/−11) and the test file (+22/−14).

  • Test run. Python 3.13.18, fresh .venv, pip install -e ".[dev]", the brief's env vars. The readings test gives 15 passed, and --collect-only gives 15 tests collected.

  • Style. black -l 79 --check tests/test_track_b_readings_20261023.py reports "1 file would be left unchanged", and ruff check reports "All checks passed!".

  • Mention counting. Each marker contains exactly one MENTION match, and no MENTION match can extend into a marker's "Source", because only [\W_] and an optional s may sit between "source" and "conflict". So equal counts mean no stray mention, apart from the id-containing case in finding 4.

  • Prose against code (apart from the findings). I read the note paragraph (:3278-3292) and the module docstring (:5-11) against the code. The per-id exemption (:94-98), the exact set (:104), the four allowed files by package path (:105-111), the whole-id documentation check over docs/design/track_b_*.md (:116-120), the per-note readings check (:127-129) and the quote check (:161) all do what the prose says. The location check allows any of the four modules for any reading. A G reading's marker moved from gross_benefits.py:3933 into arf.py gives 15 passed. The prose says "each in the G, R2, R3 or grace module", so this matches it.

  • Over-strictness. I scanned each .py/.yaml/.yml file in the Track B package on both merged trees. The wider MENTION and the old source\s+conflict give the same count in every file. In every non-exempt file, mentions = markers = us:oasdi occurrences (counts under finding 1). The only mismatch is Track B insured status: quarters of coverage; fully, currently and disability insured #562's insured_status.py (13 mentions, 11 markers, the two wrapped markers), which is exempt. git ls-tree shows that the only non-Python, non-YAML file in the package on all three trees is README.md. Neither the wider MENTION nor the rglob scan breaks on any of the three trees.

  • Scratch merges. For each PR I checked out a detached 079c33da and ran git merge --no-ff --no-commit <sha>. For Track B insured status: quarters of coverage; fully, currently and disability insured #562 (168bb3a8), only tests/README-tiers.md and tests/tier_counts.json conflicted, and I took ours for both. Track B G part 2 and R2 part (b): deductions before reduction; SSA's operational saving clause #563 (dbdceac5) merged without conflicts. The readings test gives 15 passed on each merge, and so does the patched test above. I ran git merge --abort after each, and git status --short was empty.

  • Mutations. Each one ran -k "both_directions or documented_in" at the head unless marked "full". After each I restored with git checkout 079c33da -- src tests docs and git clean -fq -- src tests docs, and git status --short printed 0 lines.

    # Mutation Expected from the prose Result
    R5-1 Truncated us:oasdi-parent-entitlement marker in ret_grace.py Both fail 2 failed
    R5-2 R5-1, plus the truncated id in OTHER_ROUNDS Whole-id test fails 1 failed, 1 passed
    R5-3 Delete the grace marker (ret_grace.py:461) Exact-set test fails 1 failed, 1 passed
    R5-4 Drop ...-sole-full-deduction-zero-dual-composition from OTHER_ROUNDS Exact-set test fails 1 failed, 1 passed
    R5-5 Undocumented marker in a new insured_status.py Exempt: pass 2 passed
    R5-6 Same undocumented id in insured_status.py and ret_grace.py Both fail 2 failed
    R5-7 Undocumented marker in a new extra.py Both fail 2 failed
    R5-8 Grace marker truncated to ...-rib Both fail 2 failed
    R5-9 Wrapped id in ret_grace.py Fail 2 failed
    R5-10 # Source conflict: us:oasdi-... Fail 2 failed
    R5-11 ...-count-intervalX Fail 2 failed
    R5-12 ...-count-interval_v2 Fail 2 failed
    R6-13 Prose "source conflict" in b2.py's module docstring Fail 2 failed
    R6-14 Trailing . on the grace marker Fail 2 failed
    R6-15 ) after the grace marker Fail 2 failed
    R6-16 Undocumented id in _insured_status_qc.py and gross_benefits.py Both fail 2 failed
    R6-17 # Source-conflict us:oasdi-... Fail 2 failed
    R6-18 Lowercase # source conflict us:oasdi-... Fail 2 failed
    R6-19 Undocumented marker in parameters/__init__.py Fail 2 failed
    R6-20 Wrapped marker in a new insured_status.py Exempt: pass 2 passed
    R6-21 Grace id wrapped at a hyphen in every note Whole-id test fails 1 failed, 1 passed
    R6-22 Grace id ...-rib-dibX in every note Whole-id test fails 1 failed, 1 passed
    R6-23 , after the grace marker Fail 2 failed
    R6-24 Source conflict (two spaces) Fail 2 failed
    R6-25 # See the source conflicts above. Fail 2 failed
    R6-26 The marker text in a string literal Parsed as a marker: fail 2 failed
    R6-27 (full) G note misspells ...-temporary-partial-deduction as ...deductionX Fail 1 failed, 14 passed
    28 Split mention # Source / # conflict us:oasdi-... Fail 2 failed
    29 Uppercase US:OASDI-brand-new marker Fail 2 failed
    30 Undocumented marker in a new parameters/insured_status.py Not exempt: fail 2 failed
    31 Logged id duplicated into parameters/ret_v1.yaml Location check fails 1 failed, 1 passed
    32 Grace marker followed by (see R2) Allowed (ends at whitespace) 2 passed
    33 (full) G reading's marker moved from gross_benefits.py to arf.py Allowed by the prose 15 passed
    34-38 Reworded marker or bare id (finding 1) Fail 2 passed
    39-40 .YAML and .pyi files (finding 2) Fail 2 passed
    41-44 (full) Heading variants (finding 3) Fail 15 passed
    45-46 "resource conflict" and "the source. Conflicts" prose (finding 4) Not a source conflict 2 failed (over-strict)
    47 (full) xus:oasdi-... as the only note mention (finding 5) Fail 15 passed

What I couldn't check


Generated by Claude Code

- STRAYS replaces the mention count. Once its markers are removed, a
  scanned file may hold no "source(s)" joined to "conflict" by
  whitespace, #, - or _, no "us" joined to "oasdi" in any case or
  separator, and no id without its "us:".
- The scan reads .py, .pyi, .yaml and .yml files with the suffix in any
  case, as UTF-8.
- The insured-status modules keep their own register and test (#562), so
  the scan skips them outright.
- DOCUMENTED gets a left boundary.
- Heading lines, code blocks included, after removing leading
  whitespace, > and list markers:
  - ATX lines;
  - lines that open with ** or __;
  - HTML h1 to h6, closed or not;
  - setext runs.
  The test compares their text after decoding entities and removing
  markup.
- The G note states each rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Ready for hub review

This is an independent round-8 review (fix delta plus a full pass of the marker test) by a Claude Opus 5.5 cloud session, for the Track B readings session.

Verdict: APPROVE at 5853c77ea92be122ef1db61a50ae5c945f33d806. This is the PR head on GitHub at review time.

All six round-7 findings are resolved. I ran 127 mutations. Rounds 5 to 7's cases, the brief's listed forms and my own cases all behave as the note and docstring say, with four exceptions, all low or nit. The readings test passes on all three scratch merges, and so does #562's register test. The full pass found no input that lets a stale, missing, truncated, unparseable or undocumented marker pass where the prose says it can't. It also found no rule that breaks a legitimate marker or a file at the head, at #562's f9287518 or at #563's dbdceac5. Three low gaps and four nits remain, listed below so they can all be closed in one pass. None of them blocks.

Findings

1. Low: an <h1>–<h6> opening tag with > in a quoted attribute hides its heading

tests/test_track_b_readings_20261023.py:108-111 (HTML_HEADING). [^>]*> ends the opening tag at the first >, even inside a quoted attribute value. The note (docs/design/track_b_g_gross_benefits.md:3316) says the test reads "the text after each <h1> to <h6> opening tag". In this counterexample the read text starts with b">, so the heading passes.

$ printf '\n\n<h2 title="a>b">Needs Max'"'"'s judgment</h2>\n\n' >> docs/design/track_b_g_gross_benefits.md
$ python -m pytest -p no:cacheprovider -q tests/test_track_b_readings_20261023.py
15 passed

The single-quoted form <h2 data-x='>'> fails (1 failed, 14 passed), but only because the '> left over after the tag ends happens to start with characters JUDGMENT skips. Fix: let the tag body skip quoted values, <h([1-6])\b(?:[^>"']|"[^"]*"|'[^']*')*>. A shorter fix is to write "up to the first >" in the note.

2. Low: the _module_markers docstring says a reworded marker fails while "its id's words" survive

:128-130. The code catches the id's words only after oasdi (STRAYS[2], :90). A reworded marker whose id has lost us:oasdi passes:

$ echo '# Conflicting sources: brand-new-undocumented' >> src/populace_dynamics/track_b/ret_grace.py
$ python -m pytest ... tests/test_track_b_readings_20261023.py
15 passed

The note (:3299-3301) gets this right: a marker fails only "while any of these survive in it", and "these" are the three patterns. The module docstring (:7-8) is also right. Fix: in the function docstring, change "its id's words" to "oasdi and two of its id's words".

3. Low: the note doesn't give the id grammar, and the code is narrower than "ends at a colon, whitespace or the end of the file"

:74 (ID) and :77, against the note at :3287-3288. In the code, an id is us:oasdi- followed by hyphen-separated runs of lowercase letters and digits. Read alone, the note implies an id is whatever comes before the colon, whitespace or end of file. A marker with an underscore or a dot in its id fails even when the id is logged in OTHER_ROUNDS and documented in the R2 note:

# Source conflict us:oasdi-ret_grace-new   (+ OTHER_ROUNDS, + R2 note)  -> 2 failed, 13 passed
# Source conflict us:oasdi-ret.grace-new   (+ OTHER_ROUNDS, + R2 note)  -> 2 failed, 13 passed

No id in the repo uses those characters. At the head, this printed nothing:

git grep -n -i -E "us:oasdi-[a-z0-9-]*[^a-z0-9: \n.,)\`-]" -- src docs/design/track_b_*.md \
  | grep -v "us:oasdi-[a-z0-9-]*[\`'\"*/;]"

#562's register test uses the same grammar (READING, tests/test_track_b_insured_status_readings.py:22). So no legitimate marker breaks today, and I rate this low. Fix: add a clause to the note, for example "an id is us:oasdi- and then words of lowercase letters and digits joined by single hyphens".

4. Nit: "letter" means A to Z in the code but any letter in the prose

:82 and :94, against the note at :3291 and :3305. Both boundaries are ASCII classes, so an accented letter counts as "not a letter":

$ echo '# résource conflict' >> src/populace_dynamics/track_b/runner.py          -> 2 failed, 13 passed
  (the prose allows it: a letter sits just before "source")
U marker + OTHER_ROUNDS, documented only as "See us:oasdi-brand-new-undocumentedé."
  (é directly after the id)                                               -> 15 passed
  (the prose rejects it: a letter sits just after the id)

Neither form appears in any tree. Fix: write "no letter A to Z" and "no letter A to Z, digit, ..." in the note and the comments. The alternative is [^\W_]-style Unicode classes in the code.

5. Nit: the note doesn't say that a scanned file must be UTF-8

:141 reads with encoding="utf-8". A new extra.py holding b"# caf\xe9\n" gives 2 failed, 13 passed (UnicodeDecodeError). This is the safe direction. The "Files it reads" bullet (:3280-3285) doesn't mention the encoding, though the brief says the commit claims it. Fix: add "read as UTF-8; a file that doesn't decode fails".

6. Nit: "verbatim up to whitespace" applies to the capture's whitespace, not the quote's

:247 collapses the capture's whitespace runs but not the quote's. A quote edited to "if she became entitled" (two spaces) gives 1 failed, 14 passed. That is what the docstring (:13-15) says. The note (:3329-3330) could be read as tolerating whitespace on both sides. Fix (optional): write "with the capture's whitespace runs read as single spaces".

7. Nit: heading spellings outside the stated lists still pass

The note lists exactly what it removes and which apostrophes it accepts, so each of these is a stated gap, not a misstatement. I list them in case you want to close them in this pass. Each was appended to the G note, and each gives 15 passed:

  • ## Needs ~~Max's~~ judgment (strikethrough inside the phrase; ## ~~Needs Max's judgment~~ fails);
  • Max´s (U+00B4), Max′s (U+2032), Max's (U+FF07);
  • U+200E (left-to-right mark) before a space;
  • ## &lt;Needs Max's judgment&gt; and ## <Needs Max's judgment>: the entities are decoded first, then <...> is removed as a tag. The note says this, in that order;
  • a Cyrillic е in "Needs";
  • <b>Needs Max's judgment</b> and *Needs Max's judgment* on their own lines. The note counts only lines that start with ** or __.

Round-7 findings

  1. Reworded marker or bare id (medium): resolved. STRAYS (:79-91) runs over the text with its markers removed (:142-144). All five round-7 rewordings give 2 failed, 13 passed. So do the brief's bare forms (US:OASDI-..., us-oasdi-..., us_oasdi-..., us : oasdi-..., oasdi-x-y) and "US OASDI" prose. "status OASDI" and "OASDI-covered" pass. This check is stronger than the us:oasdi count I proposed in round 7, because it also catches us-oasdi and oasdi-x-y.
  2. Skipped suffixes (low): resolved. :137 lower-cases the suffix, and SOURCES includes .pyi (:73). New files ending .YAML, .Yml, .pyi and .PY each give 2 failed. .json passes, which the note allows.
  3. Heading variants (low): resolved. All four round-7 variants and the control give 1 failed, 14 passed, My 37 further heading forms (table rows 90-126) also behave as the prose says, apart from H8 (finding 1). The remaining gaps are findings 1 and 7.
  4. MENTION boundaries (nit): resolved. "resource conflict", "the source. Conflicts" and a grace id renamed to contain source-conflict everywhere all give 15 passed, as does the control rename.
  5. DOCUMENTED left boundary (nit): resolved. :94. The xus:oasdi-... case gives 1 failed, 14 passed, and its control gives 15 passed.
  6. "verbatim" (nit): resolved. The note (:3329-3330) now says "verbatim up to whitespace". See finding 6 for one remaining ambiguity.

Checked and sound

  • Head and delta. git rev-parse HEAD and gh api repos/.../pulls/565 --jq .head.sha both give 5853c77ea92be122ef1db61a50ae5c945f33d806. Its parent is 079c33da. git diff --stat 079c33da 5853c77e touches only docs/design/track_b_g_gross_benefits.md and the test file (177 insertions, 48 deletions). dbdceac5 is not an ancestor of the head: the merge base is 03530e8, and Track B G part 2 and R2 part (b): deductions before reduction; SSA's operational saving clause #563's head has 4 commits the PR head lacks. So the Track B G part 2 and R2 part (b): deductions before reduction; SSA's operational saving clause #563 merge below is a real check.

  • Test run. Python 3.13.18, fresh .venv, pip install -e ".[dev]", the brief's env vars: 15 passed. --collect-only gives 15 tests collected.

  • Style. black -l 79 --check reports "1 file would be left unchanged". ruff check reports "All checks passed!". grep -cP '[^\x00-\x7F]' prints 0.

  • Prose against code. I read the note passage (:3278-3332), the module docstring (:1-16), every constant's comment and both helper docstrings against the code. Apart from findings 1-6, each rule does what the prose says. That covers the scan scope and exemption (:133-140), the marker form and its end (:77), the three STRAYS (:82, :86, :90), the exact set and the four modules (:187-197), whole-token documentation in any docs/design/track_b_*.md (:200-206), each note naming its own readings (:213-215), CONTAINERS, ATX, the bold rule, setext runs (:150-175), entity decoding and MARKUP (:178-180), and JUDGMENT's leading skip, apostrophes and "judgement" (:119-122). No logged id is a hyphen-word prefix of another, so a marker wrapped at a hyphen can't parse as a different logged id. I checked every ordered pair of the 21 logged ids by script.

  • Over-strictness. I ran each STRAYS pattern, before and after marker removal, over every .py/.pyi/.yaml/.yml file in the package, exempt files included. I also ran _headings/_open_judgment_headings over the three notes. The trees were the head, raw f9287518, raw dbdceac5 and all three merges. No non-exempt file has a stray, and neither do the exempt insured_status.py (13 markers) or _insured_status_qc.py (1 marker). The only unscanned file in the package is README.md. At the head and on all three merges, the three notes have 156, 117 and 15 heading lines and no open judgment heading. The raw Track B insured status: quarters of coverage; fully, currently and disability insured #562 and Track B G part 2 and R2 part (b): deductions before reduction; SSA's operational saving clause #563 trees still have open "Needs Max's judgment" headings in the G and R2 notes, but those trees don't contain this test, and Track B G/R2: decide the open readings (stacked on #563) #565 resolves them.

  • Scratch merges. I used a detached worktree at 5853c77e for each and ran git merge --no-ff --no-commit.

    Nothing was pushed, and the worktrees were removed afterwards.

  • Track B insured status: quarters of coverage; fully, currently and disability insured #562's exemption claim. tests/test_track_b_insured_status_readings.py at f9287518 reads exactly the two exempt modules. It requires each marker line to carry a whole us:oasdi-insured-... id, and it checks the register in track_b_insured_status.md. A G reading moved into an exempt insured_status.py gives 1 failed, 14 passed here, because the readings test loses that marker.

  • Mutations. I ran the full readings test file for each one. After each, I restored with git checkout 5853c77e -- src tests docs and git clean -fdq -- src tests docs. The script asserted that git status --short was empty after every row, and it was. "pass(note)" marks a case the prose allows or doesn't claim. Rows 1-33 are rounds 5 and 6, rows 34-54 are round 7, rows 55-69 are the brief's forms, and the rest are mine. In the table, U stands for us:oasdi-brand-new-undocumented.

# Mutation Expected from the prose Result
1 R5-1 truncated parent-entitlement marker in ret_grace fail 2 failed, 13 passed
2 R5-2 R5-1 + truncated id in OTHER_ROUNDS fail 1 failed, 14 passed
3 R5-3 delete grace marker fail 1 failed, 14 passed
4 R5-4 drop sole-full from OTHER_ROUNDS fail 1 failed, 14 passed
5 R5-5 undocumented marker in new insured_status.py pass 15 passed
6 R5-6 same U in insured_status.py and ret_grace.py fail 2 failed, 13 passed
7 R5-7 U marker in new extra.py fail 2 failed, 13 passed
8 R5-8 grace marker truncated to -rib fail 2 failed, 13 passed
9 R5-9 wrapped grace id fail 2 failed, 13 passed
10 R5-10 'Source conflict:' colon form fail 2 failed, 13 passed
11 R5-11 ...-count-intervalX fail 2 failed, 13 passed
12 R5-12 ...-count-interval_v2 fail 2 failed, 13 passed
13 R6-13 prose 'source conflict' in b2.py docstring fail 2 failed, 13 passed
14 R6-14 trailing period fail 2 failed, 13 passed
15 R6-15 trailing paren fail 2 failed, 13 passed
16 R6-16 U in _insured_status_qc.py and gross_benefits.py fail 2 failed, 13 passed
17 R6-17 Source-conflict hyphen fail 2 failed, 13 passed
18 R6-18 lowercase source conflict fail 2 failed, 13 passed
19 R6-19 U marker in parameters/__init__.py fail 2 failed, 13 passed
20 R6-20 wrapped marker in new insured_status.py pass 15 passed
21 R6-21 grace id wrapped at hyphen in every note fail 2 failed, 13 passed
22 R6-22 grace id ...-rib-dibX in every note fail 2 failed, 13 passed
23 R6-23 trailing comma fail 2 failed, 13 passed
24 R6-24 two spaces fail 2 failed, 13 passed
25 R6-25 '# See the source conflicts above.' fail 2 failed, 13 passed
26 R6-26 marker text in a string literal fail 2 failed, 13 passed
27 R6-27 G note ...deductionX fail 1 failed, 14 passed
28 R6-28 split mention fail 2 failed, 13 passed
29 R6-29 uppercase US:OASDI marker fail 2 failed, 13 passed
30 R6-30 U in new parameters/insured_status.py fail 2 failed, 13 passed
31 R6-31 logged id dup into parameters/ret_v1.yaml fail 1 failed, 14 passed
32 R6-32 grace marker + ' (see R2)' pass 15 passed
33 R6-33 G marker moved to arf.py pass 15 passed
34 R7-1.0 reworded/bare: # Conflicting sources us:oasdi-brand-new-undocumented fail 2 failed, 13 passed
35 R7-1.1 reworded/bare: # Conflict of sources: us:oasdi-brand-new-undocumented fail 2 failed, 13 passed
36 R7-1.2 reworded/bare: # Sources in conflict us:oasdi-brand-new-undocumented fail 2 failed, 13 passed
37 R7-1.3 reworded/bare: # Source dispute us:oasdi-brand-new-undocumented fail 2 failed, 13 passed
38 R7-1.4 reworded/bare: # Reading us:oasdi-brand-new-undocumented fail 2 failed, 13 passed
39 R7-2 marker in file with suffix .YAML fail 2 failed, 13 passed
40 R7-2 marker in file with suffix .Yml fail 2 failed, 13 passed
41 R7-2 marker in file with suffix .pyi fail 2 failed, 13 passed
42 R7-2 marker in file with suffix .PY fail 2 failed, 13 passed
43 R7-2c .json not scanned pass 15 passed
44 R7-3 heading '## Needs Max’s judgment' fail 1 failed, 14 passed
45 R7-3 heading "## Needs Max's Judgment" fail 1 failed, 14 passed
46 R7-3 heading "Needs Max's judgment\n----" fail 1 failed, 14 passed
47 R7-3 heading " ## Needs Max's judgment" fail 1 failed, 14 passed
48 R7-3 heading "## Needs Max's judgment" fail 1 failed, 14 passed
49 R7-4a 'resource conflict' prose pass 15 passed
50 R7-4b 'the source. Conflicts' prose pass 15 passed
51 R7-4c rename grace id to ...-source-conflict-rib-dib everywhere pass 15 passed
52 R7-4d control rename ...-other-rib-dib pass 15 passed
53 R7-5 U marker, OTHER_ROUNDS, doc only as xU fail 1 failed, 14 passed
54 R7-5c control: doc as U pass 15 passed
55 brief bare/prose: # US:OASDI-brand-new-undocumented fail 2 failed, 13 passed
56 brief bare/prose: # us-oasdi-brand-new-undocumented fail 2 failed, 13 passed
57 brief bare/prose: # us_oasdi-brand-new-undocumented fail 2 failed, 13 passed
58 brief bare/prose: # us : oasdi-brand-new-undocumented fail 2 failed, 13 passed
59 brief bare/prose: # oasdi-x-y fail 2 failed, 13 passed
60 brief bare/prose: # Benefits under US OASDI rules. fail 2 failed, 13 passed
61 brief allowed prose: # Insured status OASDI rules. pass 15 passed
62 brief allowed prose: # OASDI-covered work. pass 15 passed
63 brief allowed prose: # The resource conflict is handled. pass 15 passed
64 marker ends at colon pass 15 passed
65 marker ends at tab pass 15 passed
66 marker at EOF, no newline pass 15 passed
67 '## Source conflict <id>' pass 15 passed
68 '#Source conflict <id>' fail 2 failed, 13 passed
69 non-UTF-8 byte in scanned file fail 2 failed, 13 passed
70 N1 reworded, id words without oasdi: '# Conflicting sources: brand-new-undocumented' pass(note) 15 passed
71 N2 four colons, one word: us::::oasdi-x pass(note) 15 passed
72 N2b four colons, two words: us::::oasdi-x-y fail 2 failed, 13 passed
73 N3 dot separator one word: us.oasdi-x pass(note) 15 passed
74 N4 underscores: oasdi_brand_new_undocumented pass(note) 15 passed
75 N5 U+2011 hyphens without us:: oasdi‑brand‑new pass(note) 15 passed
76 N5b U+2011 hyphens with us: fail 2 failed, 13 passed
77 N6 xus:oasdi-x (one word, letter before) pass(note) 15 passed
78 N7 accented letter before source: '# résource conflict' in runner.py pass(note: letter before) 2 failed, 13 passed
79 N7b Cyrillic homoglyph 'Sоurce conflict' + no id pass(note) 15 passed
80 N8 underscore in id, logged+documented ?(note silent on id grammar) 2 failed, 13 passed
81 N9 marker id = logged id with '.' in it, logged+documented ?(note silent) 2 failed, 13 passed
82 N10 CRLF line endings on ret_grace.py pass 15 passed
83 N11 G marker moved into exempt insured_status.py fail 1 failed, 14 passed
84 N12 marker in hidden subdir .scratch/x.py fail 2 failed, 13 passed
85 N13 marker in file named INSURED_STATUS.py fail 2 failed, 13 passed
86 N14 U marker, logged, documented only as U + 'é' suffix fail(note: letter after) 15 passed
87 N15 U marker, logged, documented only in another track_b_*.md note pass 15 passed
88 N16 marker inside a docstring after other text 'x# Source conflict U' fail 2 failed, 13 passed
89 N17 READINGS G id documented only in R2 note fail 1 failed, 14 passed
90 H1 strikethrough inside: '## Needs ~~Max's~~ judgment' pass(note) 15 passed
91 H1b strikethrough whole: '## ~~Needs Max's judgment~~' fail 1 failed, 14 passed
92 H2 acute accent U+00B4 apostrophe pass(note) 15 passed
93 H3 prime U+2032 pass(note) 15 passed
94 H3b fullwidth U+FF07 pass(note) 15 passed
95 H4 LRM U+200E before space pass(note) 15 passed
96 H4b word joiner U+2060 inside fail 1 failed, 14 passed
97 H5 &lt;Needs Max's judgment&gt; pass(note order) 15 passed
98 H6 raw <Needs Max's judgment> (CM shows literal) pass(note) 15 passed
99 H7 Cyrillic e homoglyph pass(not claimed) 15 passed
100 H8 <h2 title='a>b'> fail 15 passed
101 H9 <h2> attribute with > single-quoted fail 1 failed, 14 passed
102 H10 <b> line pass(note) 15 passed
103 H11 italic-only line *...* pass(note) 15 passed
104 H12 HTML comment between words fail 1 failed, 14 passed
105 H13 numbered '## 3. Needs Max's judgment' fail 1 failed, 14 passed
106 H14 'Open: Needs Max's judgment' pass(note: starts with) 15 passed
107 H15 NBSP entity between words fail 1 failed, 14 passed
108 H16 double-encoded &amp;#39; pass 15 passed
109 H17 7 #s pass 15 passed
110 H18 #Needs no space pass 15 passed
111 H19 tab after # fail 1 failed, 14 passed
112 H20 > - ## nested fail 1 failed, 14 passed
113 H21 setext under list item fail 1 failed, 14 passed
114 H22 '= = =' underline pass 15 passed
115 H23 'judgement' fail 1 failed, 14 passed
116 H24 inline code in heading fail 1 failed, 14 passed
117 H25 link text fail 1 failed, 14 passed
118 H26 'Needs Max's' / judgment over 2 lines setext fail 1 failed, 14 passed
119 H27 html h2 unclosed multiline fail 1 failed, 14 passed
120 H28 escaped '\## Needs' pass 15 passed
121 H29 bold lead-in fail 1 failed, 14 passed
122 H30 &#8217; entity fail 1 failed, 14 passed
123 H31 closing ## fail 1 failed, 14 passed
124 H32 underscore bold fail 1 failed, 14 passed
125 H33 fenced code fail 1 failed, 14 passed
126 H34 indented code fail 1 failed, 14 passed
127 Q1 quote with double space fail 1 failed, 14 passed

What I couldn't check


Generated by Claude Code

The notes check now reads every opening, not only headings: a non-blank
line continues the line above it only when both start with a letter A to
Z after the same leading whitespace and neither holds ">" or "|"; every
other line opens, through the end of its non-blank run. The text after
each h1 to h6 tag counts too, with the tag read as ending at its first
">" and again at its first ">" outside quotes (round 8, finding 1).

An opening fails when its letters A to Z, after entity decoding, NFKD
and lower-casing, start with "needsmaxsjudgment" or
"needsmaxsjudgement", in either of two readings: with HTML tags and
Markdown link targets removed, and as written. Punctuation, apostrophes,
digits, whitespace, markup and invisible characters no longer hide the
phrase (finding 7). The note states what still can: a letter a reading
keeps, or a look-alike letter from another script.

The stray rules count only A to Z and 0 to 9 as letters and digits, even
under IGNORECASE. The note gives the id grammar, says files and notes are
read as UTF-8, and says whose whitespace the quote check collapses
(findings 2 to 6). 170 mutations behave as the note says.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis changed the base branch from trackb-g2-r2b-20261023 to master November 2, 2026 21:39
Master gained #563's last commits (dbdceac, f5a18c8) and #596; the merge is clean, and neither side's tier files conflict.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — d636d760 Deployed Nov 2, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant