M6 harness: source person sex canonically in build_realized_population (reg-3 crash-2 fix + schema audit) - #203
Conversation
…_realized_population The demographic panel carries no sex column; build_realized_population read it there via _anchor_rows, so the first real-frame execution crashed (ValueError: anchor source is missing columns ['sex'], m6_population.py:139; grading #42 comment 4972045579). Source person-constant sex from the death-records individual file (data.deaths.read_death_records) by person_id -- the same canonical attach the certified builders use (household_composition.join_demographics, disability.attach_sex) -- validating uniqueness and full coded-sex coverage over the anchor persons. Replace the demo test fixture, which baked in sex, with the real seven-column demographic_panel schema plus a real-schema death-records sibling so this defect class cannot re-hide behind a flattering fixture. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add m6_schema_audit: an explicit in-code manifest of every column each real-frame-reading M6 phase (input assembly, the m6_cells truth builders, and build_realized_population) requires from each certified loader/factory frame, plus the committed loader schemas and an audit function. A unit suite checks the manifest against the committed schemas -- and discriminates, flagging a phantom read so a green audit is meaningful, not vacuous -- while an integration_psid suite checks it against the real loaders' actual columns. This is the check whose absence let the second registered gate_m6 run crash at first real contact (grading #42 comment 4972045579); it encodes the correction that person sex is read from death_records, never from demographic_panel. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
environment_block (written to every one-shot run's .env.json sidecar) recorded python/numpy/pandas/sklearn/scipy/platform but no populace-fit / populace-frame vintage, so a scored M6/W1 run's frame-stack provenance was unrecoverable from the record (grading #42 comment 4972045579). Add a fitting_stack block: {version, git_rev} per package when importable (git_rev resolved from an editable checkout, "unknown" for a wheel), "absent" otherwise. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The runner docstring gave the registration/factory contract but never named the run env. The third registration's first crash was a fitting-stack import miss (grading #42 comment 4972045579): the single-venv provisioning named policyengine-us but not populace-fit. Document the prerequisites -- populace-fit (+ populace-frame) in a dedicated venv (the .venv-gate / W1 two-env split, since populace-fit pins scikit-learn <1.9), and policyengine-us==1.752.2 with POPULACE_DYNAMICS_PE_US_DIR -- and note build_realized_population precedes the QRF refit and needs only the base install. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n guard The third gate_m6 candidate-1 registration failed to execute (two pre-scoring crashes, one-shot unconsumed; grading #42 comment 4972045579), so it cannot authorize a scored run. Add it to _KNOWN_STALE_REGISTRATIONS alongside the two earlier graded stops, and to the runner test's stale-registration parametrize. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2.8.3's per-field list attributed sex to panels.demographic_panel, which has no sex column; record the correction in a new 2.8.3f subsection (sex is sourced from data.deaths, the certified attach), add the revision-log entry, and update the amendment-history JSON block (amendment_3f_section + next). Closes the third registration's crash-2, graded #42 comment 4972045579. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e real loaders The real-frame proof run showed read_disability_status also emits sequence+status and marital events emit origin. Add them so the committed schemas exactly match the real loaders (integration_psid drift check green); the manifest reads are unaffected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
unit 420->427 (+2 population fixture, +5 schema audit), artifact 1011->1012 (+1 stale-registration parametrize), integration_psid 800->802 (+2 real-frame schema audit). CI-equivalent recount via pytest tests/ -k tier_policy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Adversarial referee round — PR #203 (M6 sex-source patch, pre-fourth-registration)Scope per grading #42 comment 4972045579 remedy step 3: every PR claim re-derived independently; real-frame population construction executed (loaders → The load-bearing claim: one canonical sex source, patch-legal, no design choice — SURVIVEDI hunted for a competing source across every
So for the join this patch needed — sex onto anchor persons drawn from the demographic panel — there was exactly one certified pattern, and the patch mirrors it. Patch-legal; no design choice. Bonus evidence: the pre-patch §2.8.3 already contradicted itself (demo → Real-frame proof — REPRODUCED BYTE-EXACT
The single ER32000-NA record is not an anchor person, so the full-coverage invariant holds with zero slack on this vintage — if a re-staged vintage ever pulled that person into the anchor, the run raises rather than silently altering the universe. Correct one-shot behavior. Join mechanics — verified adversariallyAll probes pass: agreeing duplicate rows collapse; conflicting coded values raise; NA-only persons are excluded from the map and caught by the anchor-coverage raise; missing Schema audit — discriminating, and complete over its declared surface (probe-proven)
Everything else
FindingsBLOCKINGNone. SHOULD-FIXS1 — §10 revision counter not bumped for 3f. The doc's own convention ties each amendment to a §10 revision (3d → "§10 revision 10", 3e → "§10 revision 11", both bumped in their landing PRs — master's JSON already carries S2 — extend the audit to the projection-time native-panel surface ( S3 — S4 — test hardening (three small gaps). (a) NOTEN1 — MH4 vs ER32000 disagree for exactly 1 of 23,696 coded anchor∩marriage-file persons. That person is classified by MH4 sex in the marital truth cells ( N2 — wording in 2.8.3f: "the same canonical attach the certified deployment builders use" — N3 — raise-vs-drop divergence, endorsed: certified joins drop uncoded persons; the seed join raises for uncoded anchor persons. Dropping would silently shrink the seed universe (a design choice); raising forces any such vintage change to a human. Correct for a one-shot, and disclosed. VerdictThe core fix is correct and canonical, the proof reproduces byte-exact, the audit is discriminating and probe-complete over its declared surface, scope is clean, CI is fresh and green at head. The amend list is small and none of it touches the sex-source logic: S1 is a two-line docs-lineage fix that the fourth registration's citations should not inherit wrong; S2–S4 are cheap hardening that belongs in this PR's spirit (the audit exists to make the next crash class impossible, and S2/S4b are the two ways it can silently under-deliver). VERDICT: AMEND — land S1 (mandatory) and S2–S4 (strongly recommended, ~1 hour together), then this is merge-ready without a further referee round; re-run |
Referee S1 (#42 comment 4972996254): 3f added amendment_3f_section but left the JSON "revision": 11 and its revision-log entry uncited, breaking the 3d/3e convention (each amendment ties to a numbered revision). Bump to 12, cite "§10 revision 12" in the log entry. Also N2 wording: "certified builders" (not "deployment builders", which collides with the transport deployment-frame code). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Referee S2: add the scored-path panel-builder reads the manifest did not see. Add marital.attrs (the 9-column person_attributes schema) to COMMITTED_FRAME_SCHEMAS and manifest entries for marital_panel_builder (marital.attrs + marital.person_years) and household_panel_builder (the validated _HOUSEHOLD_SUPPORT_COLUMNS | _HOUSEHOLD_STATE_COLUMNS + cohab seed). marital.attrs now rides the phantom-read discrimination and the exact psid drift check (both green). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… a wheel
Referee S3 demonstrated _package_git_revision("numpy") returning the worktree's
HEAD because the venv lives inside a git repo (the documented .venv-wt layout) --
wrong-but-plausible provenance in a certification sidecar, worse than "unknown".
Skip locations resolving under site-packages / dist-packages so only an editable
source tree records a revision; add the numpy-is-unknown regression test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Referee S4: (a) add the _person_sex_map conflicting-coded-values raise test (a future dedup "simplification" could otherwise turn conflicts into first-wins); (b) pin the audit's expected phase set so deleting a PHASE_FRAME_COLUMN_READS entry fails a test instead of silently narrowing coverage; (c) assert the population fixture's demo columns equal COMMITTED_FRAME_SCHEMAS["demographic_panel"] so it cannot silently re-flatter. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Referee AMEND applied (comment 4972996254)All four SHOULD-FIX landed on this branch, one commit each; core sex-source logic untouched.
N2 (wording) folded into S1: §2.8.3f now says "certified builders", not "deployment builders". N1 (1-of-23,696 MH4-vs-ER32000 disagreement — pre-existing, immaterial at cell granularity) and N3 (raise-vs-drop divergence — endorsed) need no action, per your review. Tier recount after the new tests: unit 427→431 ( |
Referee verification round — fixes re-derived at head
|
What and why
The third registered
gate_m6candidate-1 run (registration 4971244215) failedto execute with two pre-scoring crashes; the second was an integration defect,
graded in #42 comment 4972045579:
build_realized_populationreadsexfrom the demographic panel via_anchor_rows(columns=("age","sex","interview"))(m6_population.py:186), butthe certified
panels.demographic_panelcarries seven columns and nosex:{person_id, period, age, sequence, relationship, weight, interview}(
panels.py:252-253). The only test over the path used a synthetic fixture thatbaked
sexinto the demo frame, so the unit suite passed while the first realexecution of the phase (
m6_runner.py:355) could not. Run 1 masked it (itsQRF-import crash at
m6_runner.py:345precedes:355).The canonical sex source (with certified-code citations)
Person sex is
ER32000from the PSID cross-year individual file, readperson-constant by
data.deaths.read_death_records(deaths.py:171-244). Thisis the single canonical attach the certified builders use whenever
person-constant sex is joined to the demographic-panel population:
data.household_composition.join_demographicsmerges sex from thedeath-records frame by
person_id(household_composition.py:400), andbuild_household_panelsources it fromdeaths.read_death_records(
household_composition.py:446-449);data.disability.attach_sexmaps sex person-by-person from the same deathrecords (
disability.py:443-446).§2.8.3already namesdata.deathsas the sex source "for the mortality slices"(line 1007). Marriage-file sex (
marriage.marriage_history, MH4) ismarriage-file-scoped — a subset universe used only inside the marital subsystem —
so it is not a competing source for the anchor persons. There was exactly one
canonical pattern to mirror; no design choice was made here.
Fix:
build_realized_populationnow takes thedeath_recordsframe and joinsperson sex by
person_idbefore the demographic seed (_person_sex_map+.assign), validating uniqueness (one coded value per person; conflictingrows raise) and full coded-sex coverage over the anchor persons (any anchor
person without a
male/femalesex raises). The runner passesinputs.death_records, whichM6HarnessInputsalready carries.Real-frame proof (population construction →
build_realized_population)Ran on the staged PSID frames (population construction precedes the QRF refit, so
no fitting stack / pe-us needed; no pre-flights, scoring, or artifact writes):
sex)build_realized_populationcompletes; every anchor person has a coded sex, so thefull-coverage invariant holds on real data — crash-2 is resolved.
Schema audit (the check whose absence let run 2 crash)
New
harness/m6_schema_audit.py: an explicit in-code manifest of every columneach real-frame-reading phase reads from each certified frame, plus the committed
loader schemas and an
audit_columnsfunction. Scope: 8 phases(
assemble_m6_inputsrequire-columns,build_anchor_frame,presence_by_wave,mortality_slices,marital_tables_from_panel,disability_pairs,earnings_frame,build_realized_population) × 9 frames(
demographic_panel,death_records,earnings_panel,disability_status,marital.person_years,marital.events,household.person_waves,cohabitation,disability_panel.person_years).tests/test_m6_schema_audit.py): manifest vs committed schemas,plus a discriminating test that a phantom read is flagged (green ≠ vacuous);
tests/test_m6_schema_audit_psid.py): manifest vsthe real loaders' columns, plus an exact committed-vs-real drift check —
both green against staged PSID (committed schemas reconciled to reality:
disability_statusalso emitssequence/status;marital.eventsemitsorigin).The population fixture (
tests/test_m6_population.py) is rebuilt to the realseven-column demographic schema plus a real-schema death-records sibling, so this
defect class cannot re-hide behind a flattering fixture.
Also in this PR
attributed
sextopanels.demographic_panel; records the crash(
m6_population.py:139, grading 4972045579), the canonical source, and the fix;adds the revision-log entry and updates the amendment-history JSON block
(
amendment_3f_section+next).contract.environment_blocknow records afitting_stackblock (populace-fit / populace-frame version + git rev whenimportable,
"absent"otherwise) — the frame-stack vintage the sidecar omitted.run_gate_m6_candidate1.pynow names the fitting-stackprerequisites (populace-fit in a dedicated venv; the W1 two-env split;
policyengine-us==1.752.2+POPULACE_DYNAMICS_PE_US_DIR).4971244215added to_KNOWN_STALE_REGISTRATIONSand therunner-test parametrize.
tier_counts.jsonunit 420→427, artifact 1011→1012,integration_psid 800→802 (CI-equivalent
pytest tests/ -k tier_policy).Does not touch
gates.yaml,runs/, or any floor. Do not merge — anadversarial referee round (including real-frame population construction) follows.
🤖 Generated with Claude Code