M6: seed sub-15-at-anchor persons at certified marital entry (implements ratified 3g) - #210
Conversation
Implements the ratified amendment 3g pin (§2.8.2g, merged 92ad162). In marital_panel_builder, replace the unconditional override start_exposure_year := anchor_wave with the clamp start_exposure_year = max(anchor_wave, birth_year + START_AGE). For the bulk (anchor_wave >= birth_year + START_AGE) this is byte-unchanged; for the sub-START_AGE-at-anchor class (anchor_wave < birth_year + START_AGE, the reg-5 crash class, graded #42 comment 4979269487, forensics 4979437110) it is the certified marital person_years entry (birth_year + START_AGE), which the subsequent entry-row read finds by construction. The read still reads the certified person_years row (never an assumed constant), the truth side is untouched, and the frozen v3 floor plus every gated denominator stay byte-identical. START_AGE from populace_dynamics.data.transitions; birth_year already on attrs. The certified entry-row raise stays (its cause is removed). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add the crash-class fixture the born-1980-1982 marital builder fixtures lack (reg-5, forensics #42 comment 4979437110), covering the three pinned cases: - seeds a born-2001 person anchored 2015 at their certified marital entry (2016), never_married, in holdout_ids, with the entry row at 2016; - drops a born-2008 person (birth+START_AGE = 2023 > the 2022-clipped censor) via the existing start_exposure <= censor filter, neither seeded nor held; - reads a certified *married* entry row for a sub-START_AGE-at-anchor person and seeds them married (the N3 discrimination: the builder reads the certified row, it does not assume never_married). Discrimination confirmed: with the pre-3g override restored in the working tree, all three raise the exact reg-5 signature "certified marital panel has no entry row at anchor for person_ids [20]". Bump the unit tier count 434 -> 437 in tier_counts.json to match. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The fifth gate_m6 registration (4976428384, graded #42 comment 4979269487) failed to execute in the seed-1 scoring projection on the marital entry-row gap that amendment 3g closes; forensics round-2 is #42 comment 4979437110. Add it to _KNOWN_STALE_REGISTRATIONS and the freshness-guard parametrize so it can never authorize a scored run, and extend the lineage comment. Bump the artifact tier count 1013 -> 1014 for the added parametrize case. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Adversarial referee — PR #210 (amendment 3g implementing patch)Independent re-verification against the ratified §2.8.2g pins (master 92ad162), the reg-5 grading (4979269487), and forensics round 2 (4979437110). Fresh worktree at head 853134b, own venv (py3.14, two-stack: policyengine-us 1.752.2 + populace-fit/populace-frame + scikit-learn 1.8.0), real-frame work read-only through the harness loaders exactly as forensics — no scoring, no 1. Ratified-pin fidelity — exact transcription, verified
2. Real-frame proof — reproduced independently, every number matchesRead-only, harness loaders exactly as forensics (
Bonus confirmation: the unclamped master builder on the full anchor still raises the reg-5 signature, and its 3. Discrimination — proven both directions
4. Mechanics
FindingsBLOCKING — none. SHOULD-FIX — none. NOTE-1 (routes to the design lane, not this PR): §2.8.3f manifest now understates the builder's reads. The clamp reads NOTE-2 (comment currency; may ride this PR or the next): (a) the new clamp comment says "the read below (:200-205)" — the insertion itself shifted the read to VerdictVERIFIED — ready to merge. Exact transcription of the ratified §2.8.2g pins; the real-frame proof reproduces to the digit including bulk byte-identity; the tests discriminate in both directions; the guard, tiers, format, CI, and mergeability all check. The two notes are non-blocking (one is design-lane routing by construction, one is comment text). Referee protocol: read-only real-frame verification through the harness loaders in a disposable worktree; no |
…carrier) S1: PR #210 (3g impl) merged before this PR without the birth_year manifest fix and no open PR touches m6_schema_audit.py, so that lane is closed — reassign the one-token follow-up to the 3h implementing patch; carve out "3h in this docs PR edits no manifest". S2: birth_store is write-only dead state (steps.py:471 into state.fertility, read by no runner phase) — pin the actual carrier: publish roster_absent_births via _publish_draw_output into the entrants block (m6_runner.py:909-920) next to synthetic_births, so the record is published not just stored. Also fixes the clamp ref (panel_builders.py:194-197) and birth_store :471. Prose + §10 JSON. Docs-only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…on domain law (closes reg-6 crash) (#216) * M6 amendment 3h: add §2.8.2h fertility/open-additions roster-materialization domain law Adds the §2.8.2h prose section (mirrors §2.8.2g conventions), the domain law separating the frame-independent at-risk SCHEDULE (scoring) from the simulated- mortality ROSTER (materialization): scheduled maternal births materialize only for roster-present mothers; a dead mother's scheduled birth is dropped with report-only reconciliation, closing the reg-6 crash (guard steps.py:412 raise on {782173}). Adjudicates the three resolution options (drop-with-reconciliation adopted over re-draw / keep-raising), works the determinism / report-only-bias / certified- scoring-invariance obligations, and includes the sibling sweep (merge-vs-materialize arm-parity across all wave-loop open-addition paths). Cites forensics 4984997277 and grading 4984699959. Docs only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * M6 amendment 3h: fold §2.8.9 — item (iii) fertility disclosure → law; residual decisions one→two Item (iii) (step-4 fertility materialization) is promoted from "disclosed rather than fixed" to closed by amendment 3h (§2.8.2h). The residual-open-decisions summary now records two closed decisions (3g marital universe + 3h fertility roster materialization), each tied to the registration failure that surfaced it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * M6 amendment 3h: revision-log entry (§10 revision 14) + correct stale apply_fertility line-ref Adds the amendment-3h revision-log bullet (→ §2.8.2h, §10 revision 14). Corrects the pre-existing stale ref steps.py:401-433 → steps.py:440-472 in §2.8.9 item (iii) (apply_fertility is at 440-472 at HEAD; 401-433 fell inside materialize_maternal_births). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * M6 amendment 3h: §10 JSON — revision 13→14, amendment_3h_section, residual + mechanical-alignment folds Bumps the design-parameters revision to 14; adds amendment_3h_section (the dense forensic ledger for 3h mirroring amendment_3g_section); promotes residual_open_ decisions one→two (3g marital + 3h fertility roster); folds mechanical_alignments item (iii) from "disclosed not fixed" to governed by 3h (and corrects the stale apply_fertility line-ref). JSON block validated parseable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * M6 amendment 3h: fix sibling-sweep line refs (advance_age steps.py:137, allocate call site) Self-review catch: the aging row cited steps.py:434 (advance_age is at :137, wired aging=advance_age at assembly.py:428); the synthetic-id row now cites the allocate call site (steps.py:418) and the allocator definition (loop.py:49) distinctly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * M6 amendment 3h: B1 — add the live scheduled-realized-openers sweep row; re-ground immigrant row Referee BLOCKING-1: the sibling sweep missed a live row-attaching wave-loop path. Entrants ride loop-native SCHEDULED_ENTRIES_KEY metadata (loop.py:192-254, concat at period top before mortality), live for the 2017/2019 opener cohorts (246+36), NOT a missing PeriodModules step. Adds the scheduled-realized-openers row (loop-native, fresh realized ids keyed to no removable person, overlap-guarded, ordinals pre-seeded → no KeyError shape → holds by construction) and re-grounds the immigrant row as dormant (nothing schedules immigrant frames; entrants report hardcodes immigrant_cohorts:0, m6_runner.py:914). Both the §2.8.2h table and the §10 JSON. Docs-only. The law survives; the enumeration is now complete. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * M6 amendment 3h: S4 — refresh stale line pins (simulate_fertility :469, marital merge :309-314, paternal :389-391) Referee SHOULD-FIX-4: simulate_fertility is called at steps.py:469 (:467 is the else); the marital sim_years left-merge is at assembly.py:309-314 inside fertility_step (:412 is the household merge, and household_step consumes marital only as conditioning); the paternal-shadow docstring sentence spans steps.py:389-391. Prose + §10 JSON. birth_store :471 and the clamp :194-197 land with S2/S1. Docs-only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * M6 amendment 3h: S1 (erratum owner) + S2 (reconciliation publication carrier) S1: PR #210 (3g impl) merged before this PR without the birth_year manifest fix and no open PR touches m6_schema_audit.py, so that lane is closed — reassign the one-token follow-up to the 3h implementing patch; carve out "3h in this docs PR edits no manifest". S2: birth_store is write-only dead state (steps.py:471 into state.fertility, read by no runner phase) — pin the actual carrier: publish roster_absent_births via _publish_draw_output into the entrants block (m6_runner.py:909-920) next to synthetic_births, so the record is published not just stored. Also fixes the clamp ref (panel_builders.py:194-197) and birth_store :471. Prose + §10 JSON. Docs-only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * M6 amendment 3h: S3 — restate the option-(ii) rejection on fabrication grounds Referee SHOULD-FIX-3: "a re-draw shifts every downstream per-person stream" is architecture-false under the keyed ProjectionRNGRegistry (rng.py isolates every (period,module)/person stream; extra fertility-stream consumption shifts only that stream's own later child-sex draw, never another module/person/period). The rejection stands on fabrication alone — a re-draw materializes a birth the frame-independent schedule never scheduled, breaking the schedule↔materialization correspondence. Prose table cell + §10 JSON restated. Docs-only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * M6 amendment 3h: NOTE-1/2/3 precision refinements NOTE-1: name the one same-stream consumer (child-sex draw, steps.py:424-426) in the byte-unchanged claim and pin the comparison baseline (pre-patch aborts before the sex draw; only a hypothetical mother-present roster would shift same-wave sexes). NOTE-2: make the same-wave KeyError safety's reliance on eligibility filters explicit (earnings age>=15 steps.py:240; claiming age>=50 steps.py:342 exclude age-0 newborns). NOTE-3a: per-draw drop count is bounded by absent fertile woman-YEARS (parity loop marital.py:317-341), not by the 10 members. NOTE-3b: label discriminating-test assertion (c) a rewiring tripwire (holds by signature — simulate_fertility takes no roster arg), not a filter property. Prose + §10 JSON. Docs-only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Summary
Implements the ratified amendment 3g (§2.8.2g in
docs/design/m6_projection_engine.md, merged 92ad162, #209) — the marital projection domain law for sub-START_AGE-at-anchor persons. This is a zero-discovery transcription of a fully pinned design: the clamp, the tests, and the guard are all specified in §2.8.2g's Pins and Implementing patch text.The closed-panel anchor universe (
build_anchor_frame) admits minors with no age filter.marital_panel_builderoverrodestart_exposure_year := anchor_waveand then demanded the certifiedperson_yearsentry row at that wave, but the certified maritalperson_yearsbegin atbirth_year + START_AGE(START_AGE = 15). Any person withanchor_wave < birth_year + START_AGEhad no certified row at the anchor and the builder raised — the fifth-registration execution failure (ValueError: certified marital panel has no entry row at anchor; graded #42 comment 4979269487, forensics round‑2 comment 4979437110).The patch
One-line clamp in
marital_panel_builder(engine/panel_builders.py), mirroring the adjacent censor-clip idiom:anchor_wave ≥ birth_year + START_AGE): equalsanchor_wave, byte-unchanged.anchor_wave < birth_year + START_AGE): equalsbirth_year + START_AGE, the certified risk-set entry, which the subsequent entry-row read then finds by construction. The read still reads the certifiedperson_yearsrow (never an assumed constant) — the load-bearing N3 point.START_AGEfrompopulace_dynamics.data.transitions;birth_yearalready onattrs. The clamp lives only in the projected-side builder; the truth side (build_marital_panel) is untouched, so the frozen v3 floor and every gated denominator stay byte-identical. The certified entry-row raise stays (its cause is removed, not the invariant). Nogates.yamlcell, noruns/artifact, no floor, no schema-audit contract changes.Adopted option B (seed-at-marital-entry) over A (exclude-and-mark): A's symmetric exclusion would move the frozen
first_marriage.18-29|femaletolerance0.356 → 0.355, breaking byte-identity, which the ratified lock forbids.Discrimination evidence
Three tests in
tests/test_m6_panel_builders.pycover the crash class the born-1980–1982 fixtures lack (a born-2001 never_married seed, a born-2008 censor-drop, and a certified-married-entry-row N3 case). With the pre-3g override temporarily restored in the working tree, all three fail with the exact reg-5 signature:Restoring the clamp makes all three pass. The married-entry-row test is the N3 discriminator: an assumed-
never_marriedseed would read the wrong state and fail.Real-frame proof (read-only; no scoring, no artifacts)
Patched builder run over the realized anchor (seed-0 crash context) via the production loaders, compared in-memory against the unclamped origin/master builder:
START_AGEclassbirth+15 = 2023 > 2022)birth+START_AGE, 0 duplicates10187(born 2008) censor-dropped by the 212-ruleEvery number matches the ratified amendment. reg-5 id
10187is the one born-2008 member among the reported ten and is correctly censor-dropped, consistent with the 212-drop rule — not a divergence.Guard and mechanics
4976428384(graded Candidate 2 design: latent-permanent conditioned chained QRF (research memo) #42 comment 4979269487) in_KNOWN_STALE_REGISTRATIONSand the freshness-guard parametrize.unit434 → 437 (the three builder tests),artifact1013 → 1014 (the parametrize case);tier_counts.jsonupdated,test_tier_policygreen on full collection (2,932 items).black -l 79clean; three small commits.Amendment merge 92ad162 (#209) · forensics #42 comment 4979437110 · grading #42 comment 4979269487.
🤖 Generated with Claude Code