M6 design amendment 3g: marital projection domain law for sub-15-at-anchor persons (§2.8.2 pin correction, closes reg-5 crash) - #209
Conversation
…sing-entry-row) The pin claimed _valid_persons resolves the missing-entry-row case by construction; it tests the certified start_exposure=birth+START_AGE <= censor BEFORE the builder overrides start_exposure:=anchor_wave, so person-years presence at the anchor actually requires anchor_wave >= birth+START_AGE. Points to the new §2.8.2g domain law. Closes reg-5 crash (forensics #42 4979437110). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nd item (iii) §2.8.9's 'Residual open decisions: none' is falsified: the marital projection had no domain law for the sub-START_AGE-at-anchor class build_anchor_frame admits. Dated correction points to §2.8.2g. Item (iii)'s 'children fall outside holdout_ids and every gated band' holds for synthetic fertility newborns but was falsified for anchor-present minors (in holdout_ids, aging into first_marriage.18-29) — clarified. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…judication) The reg-5 crash class = 2850 sub-START_AGE-at-anchor children (build_anchor_frame has no age filter; certified marital person_years start at birth+15). Adjudicates option B (seed-at-marital-entry, start_exposure=max(anchor_wave, birth+START_AGE)) over A (exclude-and-mark): A perturbs the frozen v3 first_marriage.18-29@2019 denominator (281/3224 = 8.7% persons / 9.0% weight, verified read-only) -> floor not byte-identical -> dies; B is projected-side-only -> floor byte-identical. Leak adjudicated empirically: certified entry row never_married for all 2850, earliest married age 19 -> seed is a structural constant -> leaks nothing. Pins the patch, discriminating test, and scope. Closes reg-5 (graded 4979269487, forensics 4979437110). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…evision 13)
Adds the revision-log finding->section entry; bumps the design-parameters JSON
revision 12->13; adds amendment_3g_section; corrects builders.marital_universe
(the false 'resolves the missing-entry-row case' claim) and
scored_run_harness.residual_open_decisions ('none' -> one, closed by 3g); extends
next with the reg-4 abort / reg-5 crash / amendment-3g chain. JSON validated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Adversarial design referee — PR #209 (amendment 3g, §2.8.2g marital projection domain law)Verdict: SPEC SOUND (ratifiable after listed fixes). 0 BLOCKING · 2 SHOULD-FIX · 3 NOTE. I re-derived every load-bearing number independently on the real PSID panel (run-5 venv, read-only through the harness loaders — nothing written to any held worktree, Independently re-derived class counts (real data)
The A-kill — survives (both branches)
The B-leak — verdict holdsAll 2,850 certified entry rows at
FindingsSHOULD-FIX 1 — the "marry at age ≥19" claim is false. SHOULD-FIX 2 — NOTE 1 — asymmetric-A bias direction is inverted. NOTE 2 — NOTE 3 — data-quality aside (out of 3g scope). The MH file's pre-15 marriage-episode start ages include an age-3 record; 23 pre-15 persons land in-universe and are carried Mechanics & patch pin — all clean
Referee verification: read-only via the harness loaders on the run-5 venv; scratch confined to my own dir; my worktree removed after posting. |
S1: earliest first-marriage EVENT in the class is age 18 (pid 2852062, born 2004, 2022); earliest married person-year age 19 (allow_exact_matches=False); 9 of 11 n_marriages>0 have dated events. Leak conclusion unchanged (every event strictly after the age-15 seed). S2: relabel 281/3224=8.7% as the 2019 sex-pooled slice; the gated cell first_marriage.18-29|female pools 2015-2019 female-only (7832 at-risk), class contributes 157 = 2.0% rows / 2.25% weight; A-kill unchanged (any nonzero move breaks byte-identity; referee reproduced tol 0.356->0.355). N1: asymmetric-A biases the rate UPWARD not downward (verified). N2: missing[:10] is the seed-0 household side. N3: out-of-scope MH pre-15 aside (23 in-universe married-at-birth+15, born 1928-1988, none in class). All numbers independently re-derived read-only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mirror the prose corrections in the amendment-history JSON: S1 (age-18 event, 9 of 11 dated, age-19 married person-year); S2 (281/3224 = sex-pooled 2019 slice; gated cell first_marriage.18-29|female = 7832 at-risk pooled 2015-2019, class 157 = 2.0% rows / 2.25% weight); N1 (asymmetric-A biases rate UPWARD; tol 0.356->0.355, any nonzero move breaks byte-identity). JSON re-validated (json.loads OK, revision 13). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Referee fixes applied (SPEC SOUND → all 2 SHOULD-FIX + 3 NOTE addressed)Thanks for the independent re-derivation. Every number was re-verified read-only against the run-5 venv before editing; the B-over-A adjudication, the pinned patch, and the frozen-floor byte-identity are unchanged. Fixes on
Independently re-derived, matching the referee's table: class 2,850 (2,568/246/36); event age 18 / married-py age 19 / 9-of-11 dated; female-pooled cell 7,832 with class 157 = 2.0%/2.25%; asymmetric-A direction up. JSON re-validates ( |
The S2 fix (gated cell = first_marriage.18-29|female, class move 157/2.0%, not the 281/8.7% sex-pooled 2019 slice) was applied to the Step-2 prose; propagate it to the A-vs-B table rows A/B, the 'Symmetric floor-inert' pin, the JSON B-description, and the JSON next-chain so no residual pre-S2 framing remains. Sweep: only the two explicitly-labeled 'sex-pooled 2019 slice' references keep 281/3224/8.7%. JSON re-validated (revision 13). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
S2 propagation (follow-up to the fixes above). Completed the S2 relabel across the whole subsection so no residual pre-S2 framing remains: the A-vs-B table rows A/B, the "Symmetric, floor-inert" pin, the JSON B-description, and the JSON |
Referee verification round — commits 86e9354 / 63f9ca3 / 225eaa0 (head 225eaa0)Verdict: VERIFIED — ratifiable. All five findings resolved, not renamed. Re-derived every number myself on the real panel (run-5 venv, read-only); re-ran the floor at this round.
A-kill re-reproduced this round: the frozen v3 Residual-framing sweep: clean. No bare Mechanics at head 225eaa0: docs-only (1 file, +201/−9); frozen floors byte-identical (v3 sha No new findings. The referee round is closed from my side; ratifiable. |
M6 design amendment 3g — the marital projection domain law for sub-
START_AGE-at-anchor personsDocs-only design amendment (revision 13) adding §2.8.2g and correcting the §2.8.2 universe pin and the §2.8.9 "residual open decisions: none" claim. Closes the fifth-registration execution failure (
gate_m6candidate 1):ValueError: certified marital panel has no entry row at anchor. No code in this PR — the implementing patch is pinned in §2.8.2g and lands after ratification, as amendments 3d/3e did. Nogates.yaml/runs/contact.Evidence base (both cited by path+field throughout §2.8.2g):
The defect
build_anchor_frame(m6_cells.py:122-140) admits every gated-start-wave person with no age filter, so minors are in the anchor.marital_panel_builderoverridesstart_exposure_year := anchor_wave(panel_builders.py:187) and demands the certifiedperson_yearsentry row at that wave. But the certified maritalperson_yearsbegin atbirth_year + START_AGE(START_AGE = 15,transitions.py:111,260), so any person withanchor_wave < birth+15has no anchor row and the builder raises (panel_builders.py:209-214). The raise printsmissing[:10](reg-5 listed 10 ids); on the realized anchor the identical mechanism trips a single uniform class of 2,850 sub-START_AGE-at-anchor children (verified read-only: 2,568/246/36 anchored 2015/2017/2019; ages 7–14; born 2001–2008).Pin correction (uncontested)
The §2.8.2 pin claimed
_valid_persons"resolves the missing-entry-row case by construction." It does not:_valid_persons(transitions.py:265-277) testsstart_exposure_year ≤ censor_yearon the certifiedstart_exposure = birth+15, before the builder overridesstart_exposure := anchor_wave. Person-years presence at the anchor requiresanchor_wave ≥ birth_year + START_AGE. Corrected in place; §2.8.9's falsified "none" and item (iii) carry dated corrections.The A-vs-B verdict — argued from the numbers (all verified read-only)
The 2,850 are not gated-neutral: 281 (all born 2001, age 14 at the 2015 anchor, reaching 18 by 2019) sit in the truth-side gated
first_marriage.{18-29}@2019at-risk person-years — 281 of 3,224 = 8.7 % of persons, 9.0 % of F6 weight. Zero appear in any gated event; 2,569 are gated-neutral.e931c886…)first_marriage.{18-29}@2019denominator → σ + tolerance recompute → not byte-identical. Asymmetric (projected-only) preserves the bytes but scores a 2,943-person projected vs 3,224-person truth denominator → identity-guard-rejected (support.py:311-315) + rate-biasingstart_exposure ≤ censorfilter); the 281 enter the projected denominator symmetric with truthB is adopted; A dies on the ratified-frozen v3 floor constraint. B's pin: replace the unconditional override with
start_exposure_year = max(anchor_wave, birth_year + START_AGE)— byte-unchanged for the bulk, the certified risk-set entry for the gap class.B's named leak, adjudicated empirically (not merely "structurally near-certain")
The certified entry row at
birth+15isnever_marriedfor all 2,850 (0 exceptions), withmarriage_duration/years_since_dissolutionnull/zero; the earliestmarriedperson-year anywhere in the class is age 19; the 11 who marry (n_marriages > 0) marry at age ≥ 19, strictly after the seed. The seed is a structural constant carrying zero holdout information → B leaks nothing. B reads the certified entry row (the samepd.isna → never_marriedthe core applies,marital.py:100-101), not an assumed state.Implementing patch (pinned; not in this PR)
engine/panel_builders.pymarital_panel_builder: one-line clamp at:187(birth_yearalready onattrs).assembly.marital_step/m6_runnerunchanged (identical builder signature/return).test_m6_panel_builders.pygains a sub-START_AGE-at-anchor fixture (born 2001 anchored 2015 — the class the current born-1980–1982 fixtures lack) asserting pre-patch raise / post-patch 2016never_marriedseed +holdout_idsmembership, plus a born-2008 censor-drop case.gates.yaml/runs/delta (clamp reads only existingattrscolumns).What this does NOT change
Frozen floors byte-identical (
runs/m6_holdout_floors_v{1,2,3}.jsonuntouched; v3 shae931c886…remains the gated contract). No gated cell definition moves. The certified engine invariant is preserved — the raise (panel_builders.py:209-214) stays; amendment 3g removes the cause (the sub-START_AGEanchor override) so the invariant holds by construction, mirroring §2.8.3a. Harness/universe-side only.Tests
tests/test_gate_m6_floors.py(the doc-bound test): 23 passed — all asserted design-doc strings preserved.tests/test_m6_panel_builders.py: 7 passed — confirms docs-only (no code changed; the current fixtures do not exercise the crash class, the §2.8.2g gap this amendment names).Docs-only: 187 insertions, 9 deletions, one file.
🤖 Generated with Claude Code