Repository navigation
Track B: held-out data registry for every Track B and open-population gate - #560
Merged
Merged
Conversation
… commit The dynamics coordinator made one registry of held-out years, editions, tables and partitions the record for every Track B gate and every open-population gate (2026-10-21). This adds it at docs/design/track_b_holdout_registry.json with five verified prior uses, marked incomplete until B0.2's exposure inventory lands, and populace_dynamics.track_b.holdout_registry, which enforces its rules: schema v1, unique ids, symmetric disclosures, no silent shared unit, legal status histories, scored evidence for used entries, the incomplete flag, and append-only changes against the base branch. Tests: 25 unit tests, with Hypothesis properties; 16 of 16 mutants killed (docs/design/track_b_holdout_registry_mutations.json). Tiers: unit 9,958 -> 9,983. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
added a commit
that referenced
this pull request
Oct 21, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
- High: gate_m6's entry kept event years and reference years apart only in prose. Unit keys now name a declared source and its years; PSID is keyed by interview wave, and each entry's units state the gated and report-only reference and event years separately. - Overlap: two keys share a unit when the source matches and the years intersect; scope segments never narrow it, so table_19 and table19 overlap. Sources are a declared vocabulary whose catalog references must differ, which refuses alias names. Same-family relations the rule cannot see need an overlap_review entry with a reason. The coarser keys expose three more real shared units (gate_m6 with B2 and gate_m4, B2 with gate_m4), now disclosed both ways. - Used means scored: scored_evidence is structured (path, field, equals); the file must be committed, inside the repository and not a symlink, and its field must equal one of the entry's gate identifiers, each of which belongs to one gate only. - Master pushes compare against the push's before commit, or the first parent when the merge base is HEAD itself. - Registrations start as a lone candidate in a commit of their own; historical imports start as frozen or used and close when the registry is complete. - The immutable and extending field lists are specified independently in the tests; every field is typed and dates are parsed, so malformed input is reported rather than raised (fuzzed). - The birth-evidence seal excludes the new module, as it does b2.py. Tests: 62 unit tests; 36 of 36 mutants killed. Tiers: unit 9,958 -> 10,020. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- EPUF's key year is the vintage in the file's title (the 2006 file, released in 2011); the seeded keys are pinned by an independently specified test. - The source vocabulary lives in the module (SOURCES), so adding a source or family is a reviewed code change; the registry's copy must equal it. Family reviews need the outcome "disjoint", a substantive reason (no placeholders, at least 40 characters) and path:line or URL citations checked against the committed tree; an unresolved relation is disclosed instead. The two deferred EPUF reviews are now disclosures. - Historical imports start as used, and their scored evidence must have been committed before the registry was. - Scored evidence must be a runs/*.json artifact read from HEAD's tree (not the working tree, not a symlink), matched on gate, gate.name or registration_id, whose value names the gate in gates.yaml or in the module's REGISTRATIONS_OUTSIDE_GATES_YAML. - On pushes, every pair of consecutive first-parent commits since the base must append only (history_problems), so a later commit cannot hide a change. - Appended entries with malformed histories are reported, not raised. - The family-review tests use an independently specified family map and overlap rule, with fixed same-family cases. - Tests split by tier: invented registries and temporary repositories (unit, 74) and the committed registry, which reads committed run artifacts (artifact, 8). 47 of 47 mutants killed. Tiers: unit 9,958 -> 10,032; artifact 4,253 -> 4,261. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1. Preparation artifacts as scored evidence (medium). Scored runs are now a
controlled list in code, SCORED_RUNS {path: (gate, sha256)}. Evidence must
name a listed run that belongs to the entry's gate, and the committed
blob must match the pinned SHA-256. Floor builders, candidate lists and
dry runs are not listed, so they are rejected.
2. Import cutoff by pathname (medium). Historical imports are limited to
HISTORICAL_IMPORT_GATES, a code-level list, and start as used. Content
is pinned by hash, so renames, re-adds and merge-created registries
cannot launder a future gate's evidence into an import.
3. Registration after scoring (medium). Committed.registered_at walks the
registry's first-parent history; a registration must be on record at a
commit where its scored run was not yet committed.
4. History checks (medium). history_problems validates each snapshot
against its own commit's tree (evidence, citations, identifiers,
completion record), admits a new registry against empty_like, and skips
invalid snapshots as predecessors.
5. Rebase merging (medium). The committed module now checks every commit
on the pull request branch (full=False), so a rebase cannot introduce
an unchecked change and restoration.
6. Terminal-status mutant (low). The unit tests enumerate the permitted
transitions independently (EXPECTED_TRANSITIONS) and check terminal
statuses; used -> withdrawn is now killed.
7. Malformed inputs (low). Decoding, NUL and '..' paths, oversized line
numbers, non-mapping registries and malformed predecessors return
problems instead of raising.
Seeded entries: H005 cites gates.yaml:4311-4327 for its Census labels;
H003 cites the open-population design as PR #557 (draft).
Mutations: 53 of 53 killed (restored source sha256 aae22b1d...).
Tests: 98 passed, 2 skipped. Tier counts: unit 10,048 (+16), artifact
4,263 (+2).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3 of 7 tasks
1. Moving or removing a score bypassed preregistration (medium). The timing check now asks whether the scored run's exact bytes were committed, at any path, in the history of the commit that first records the entry on the first-parent chain (git hash-object, then git log -m --find-object). A score committed elsewhere and moved, or committed, deleted and restored, or committed on the base branch while the registration waited on a side branch, is refused. When git cannot answer, the check fails closed. 2. Historical-import permission could be reused for unscored units (medium). HISTORICAL_IMPORTS replaces the list of gates: each authorization binds one entry id to its gate, unit keys and scored runs, so an import under another id, with other units or with other runs is refused. A correction found by B0.2's inventory is a new authorized entry in a reviewed code change. 3. The first-parent registration rule had no regression test (low). The side-branch scenario now kills the --topo-order mutant. 4. Malformed inputs still raised (low). Entries without string ids are reported as malformed before any diagnostic reads them; JSON and YAML parser limits (a 5,000-digit integer) and NUL arguments to git return problems, or registry_at's documented ValueError and LookupError. Rules 6-8 in the registry now describe these mechanisms, and rule 7 states that a pull request touching the registry is merged with a merge commit, never rebased (the review's nonblocking point 5). Known and left to B0.2's inventory (nonblocking in the review): legacy gates gate_1, gate_2, gate_2b and gate_2c have committed scored outputs that are not yet imported; the registry stays incomplete until then. The reviewer's own counterexample scripts, replayed on this code: every import and timing bypass is refused, and the valid order still passes. Mutations: 64 of 64 killed, including the reviewer's --topo-order survivor and new checks on the authorization, the any-path timing search, fail-closed timing, malformed ids, parser limits and NUL arguments. Tests: 122 passed, 2 skipped (with the birth-evidence test). Tier counts: unit 10,059 (+11), artifact 4,263. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tests/tier_counts.json and tests/README-tiers.md conflicted. Recounted on the merged tree with pytest --collect-only -m <tier>: unit 18,189 (master's 18,088 + this PR's 101), artifact 4,263 (4,253 + 10), integration_psid 1,450, reproduction_legacy 520, oracle_policyengine 308; total 24,730. README-tiers.md had kept round-2 numbers on this branch; it now matches the manifest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
added a commit
that referenced
this pull request
Oct 23, 2026
…scored run #560's round-4 review found four legacy gates (gate_1, gate_2, gate_2b, gate_2c) with committed scored outputs beyond the registry's five seeded imports. The inventory must import each, or record that it holds out nothing a Track B or open-population gate could use. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1. Shallow history made the timing check fail open (medium). An empty find-object search is now a negative only in a complete repository: when git reports a shallow clone, committed_by returns None and the fail-closed diagnostic rejects the entry. A positive find is still conclusive. The search also runs with --no-replace-objects, so a replacement ref that orphans a commit cannot hide a committed score (the review's nonblocking environment-trust point). 2. A score added only in a merge resolution had no regression test (low). That topology is now tested; dropping -m from the search fails it. 3. Subprocess failures escaped (low). _git and _git_bytes turn TypeError and OSError (an argument list too long, a missing git, a None argument) into git-style failures, so validate reports a problem and registry_at and history_problems raise their documented LookupError. validate also checks the shape of injected import authorizations. 4. SHA-256 object ids were ignored at event boundaries (low). SHA_RX accepts 40- and 64-digit ids, so a SHA-256 push's before commit and a SHA-256 pull request head are honoured. Mutations: 70 of 70 killed, adding merge diffs not searched, shallow history trusted, replacement refs honoured, SHA-256 ids rejected, subprocess OSError escapes and authorization shapes unchecked. Tests: 130 passed, 2 skipped (with the birth-evidence test). Tier counts: unit 18,197 (+8 since round 4), artifact 4,263. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eview round 6) Round 6 (Astra, at daf0242) found one medium and one low. - Medium: a transient git failure while resolving a push's `before` commit made `base_commit` fall back to the merge base, which on master is HEAD^1, so the history check covered fewer commits and passed an edit-and-restore of immutable unit keys. A push now resolves its own `before` commit or raises LookupError; an unreadable event, or one naming no commit id, also raises. An all-zero `before` (a branch's first push) still falls through to the merge base. - The same class on pull requests: `pull_request_head` returned None for an unreadable event, and the committed-registry test then skipped the pull request's own commits. On a pull_request event it now raises. One helper, `_event`, reads the payload for both. - Low: `_git_bytes`'s TypeError and OSError handling had no test. A new test makes `hash-object` fail four ways and requires `committed_by` to return None and validation to report the timing as unanswerable. Tests: 137 passed, 2 skipped (20 new) in the two registry modules. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…stry-20261021 # Conflicts: # scripts/first_estimates_birth_evidence.py # tests/estimates/test_birth_evidence_artifact.py
Round 6 added 20 unit tests; master (2195258) adds none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 24, 2026
All 75 checks again fail the registry tests with the mutation and pass without it, against the merged source (a1fd1d99). The runner now records parametrized test ids in full; the previous record cut them at the first space, so some failing cases were missing from its lists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
marked this pull request as ready for review
October 24, 2026 15:25
…recount tiers Only the tier files conflicted; the seal lists merged cleanly and keep the registry's and S1's entries. Recounted by collection on the merged tree: unit 18,254 (master 18,125, +129), artifact 4,271 (master 4,261, +10), integration_psid 1,450, reproduction_legacy 520, oracle_policyengine 308; total 24,803. The registry and birth-evidence tests: 150 passed, 2 skipped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Merge audit (coordinator, 2026-10-24 17:08Z): merged at head
|
This was referenced Oct 24, 2026
Held-out data registry: round 7's follow-ups (unset event path, record ids, zero push boundary)
#580
Merged
Merged
This was referenced Oct 25, 2026
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The dynamics coordinator made one registry of held-out data the record for every Track B gate and every open-population gate (2026-10-21). Several lanes will cite it, so it lands on master on its own, outside B0.2's draft (#554).
What it adds
docs/design/track_b_holdout_registry.json, schematrack_b_holdout_registry.v1.gates.yaml,b2.py,disability.pyorepuf.py, with scored evidence identified by gate:complete: falseuntil B0.2's exposure inventory (docs/design/track_b_b0_2_exposure_inventory.json) exists.src/populace_dynamics/track_b/holdout_registry.py: the rules and four controlled lists, each changed only by a reviewed code change:SOURCES);REGISTRATIONS_OUTSIDE_GATES_YAML);SCORED_RUNS), each pinned to its gate and the SHA-256 of its bytes;HISTORICAL_IMPORTS), each binding one entry id to its gate, unit keys and scored runs.tests/test_track_b_holdout_registry.py, unit tier, 109 tests: invented registries and temporary git repositories, with an independently specified family map, overlap rule and transition table.tests/test_track_b_holdout_registry_committed.py, artifact tier, 10 tests: the committed registry against the committed tree and its pinnedruns/artifacts, its base commit, a pull request's own commits, and, on pushes, every first-parent commit since the base.scripts/first_estimates_birth_evidence.py: the birth-evidence seal excludes the new module, as it doesb2.py. Nothing in the historical projection imports it.Invariants (hold for every registry and every commit)
Schema and types. The schema is
track_b_holdout_registry.v1. Every field has its type, and dates are real. Malformed input, including appended entries, is reported, never raised; this is property-tested and was fuzzed with 5,000 cases.Controlled vocabulary. The registry's
sourcesequals the module'sSOURCES, so adding a source or family is a reviewed code change. Catalog references are unique, which refuses aliases. Every unit key names a declared source. The key year means what the source declares: for PSID, the interview wave; for EPUF, the vintage in its title; for publications, the edition.Overlap. A key is
source:years[:scope...]. Two keys share a unit when the source is the same and the years intersect; scope never narrows that.Disclosure. Live entries that share a unit list each other in
disclosed_overlaps. Disclosures are symmetric, never self-referential, and name only known ids. An unresolved relation is also disclosed.Family review. An entry reviews every earlier live entry of the same family that it neither shares a unit with nor discloses. A review has outcome
disjoint, a substantive reason (at least 40 characters, no placeholder words) and citations:path:linewithin a committed file, or an https URL.Provenance and status.
candidate. Against the base, a new registration must arrive alone and move on only in a later commit. Its scored run's exact bytes must not have been committed, at any path and whether or not they were later moved or deleted, in the history of the commit that first records the entry on the first-parent chain (git log -m --find-object). When git cannot answer, or the clone is shallow so an empty search proves nothing, the check fails closed; replacement refs are ignored.used, and its id, gate, unit keys and scored runs must equal an authorization inHISTORICAL_IMPORTS. A second import under another id, or one claiming other units or runs, is refused. B0.2's inventory adds an import, or a correction to one, as a new authorized entry in a reviewed code change. Imports close once the base registry is complete.statusis the history's last status.Used means scored. Each
scored_evidenceitem is {path, field, equals}.SCORED_RUNSfor the entry's gate. Its bytes are read from HEAD's tree (not the working tree, not a symlink) and must match the pinned SHA-256. Floor builders, candidate lists and dry runs are not listed, so they cannot stand as scored evidence, and a pathname cannot be reused for other content.gate,gate.nameorregistration_id, and its value equalsequals.equalsmust identify the gate ingates.yaml(key,idorregistration_id) or inREGISTRATIONS_OUTSIDE_GATES_YAML.Append-only. This holds against the base commit; between a pull request's own consecutive commits; and, on pushes, between every pair of consecutive first-parent commits since the base, where each snapshot is also validated against its own commit's tree. A newly created registry is admitted against an empty one.
id,provenance,gate,lane,source,unitsandunit_keysnever change.gate_identifiers,evidence,scored_evidence,disclosed_overlaps,overlap_reviewandhistoryonly extend. Rules only extend.completenever goes back to false.The base is chosen as follows:
beforecommit;origin/$GITHUB_BASE_REF;In CI, an unresolvable base fails the test.
Incomplete flag.
complete: truerequires the completion record to be committed.Merge with a merge commit. This PR and every later registry PR must merge with a merge commit, never a rebase, so draft commits never enter master's first-parent history (registry rule 7).
Known incompleteness. Legacy gates
gate_1,gate_2,gate_2bandgate_2chave committed scored outputs that are not yet imported. B0.2's exposure inventory imports each or records that it holds out nothing a Track B or open-population gate could use; the registry stayscomplete: falseuntil then.What the rules cannot catch mechanically. The timing rule sees scores committed to this repository, not scores computed elsewhere; gates.yaml preregistration and issue #42 cover that. The overlap rule cannot see two sources sharing underlying data, or two editions reporting the same data years; family reviews and disclosures cover that, and reviewers of each registry change must check them. Vocabulary changes are code changes, reviewed as such.
Verification
PYTHONPATH=$PWD/src:$PWD python -m pytest -q -p no:cacheprovider tests/test_track_b_holdout_registry.py tests/test_track_b_holdout_registry_committed.py tests/estimates/test_birth_evidence_artifact.pygives 130 passed and 2 skipped. The skips are the pull-request-commits test (pull request events) and the first-parent history test (pushes).-l 79) and ruff check are clean.docs/design/track_b_holdout_registry_mutations.json.d5dfef9b), unit 18,088 → 18,197 and artifact 4,253 → 4,263, for a total of 24,738, recounted withpytest --collect-only -m <tier>. Track B: held-out data registry for every Track B and open-population gate #560 takes the tier slot after Track B G v2: close #495, compute five refused configurations, one contract across G, R2 and R3 #530, so the counts are rechecked again at merge.Review history:
c299a304.9e3c6a4c.296bf2bb.5f7d995d. The reviewer's own counterexample scripts, replayed on that commit, are all refused.d5dfef9b, answered in the next commit: shallow clones fail closed, merge-resolution and replacement-ref topologies are tested, subprocess failures are reported, and SHA-256 ids are accepted.No real data is read, and nothing in
gates.yaml,engine/orruns/changes.axiom: n/a: Track B audit infrastructure; no policy encoding.
🤖 Generated with Claude Code