Repository navigation
Let an enriched docket placeholder be enriched again - #360
Merged
MaxGhenis merged 6 commits intoOct 18, 2026
Merged
Conversation
_plan_enrichment required uuid_owner[row_uuid] == the row's own key. uuid_owner records FIRST ownership and never moves, so a placeholder that was itself the successor of an earlier enrichment (geography-free -> geography-only) never owns its UUID, and its observation fell to the mint path and was refused as UUID reuse. This blocked usaspending.dod.prime_award_obligations (a2649fd9) from taking its FY2026 observation (Thesis run 38962977031). Drop that conjunct. The live-binding conditions that remain (enrichment-shaped, the row's key live, and bound to row_uuid now) are the contract and still refuse stale, superseded, retired, handed-over and reclaimed rows. The mint-path refusal now says "first bound to", since uuid_owner is not the current binding. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Regressions: - the production state (registry lines 196/249/250 for a2649fd9): the geography-only placeholder takes its first print as exactly the retire + succeeds pair Thesis's append guard admits; - the chain through main (docket entry learns a country, then the first print lands): no ceremony, one UUID, --check after each hop; - six stale rows after a chain (superseded, retired, handed over, reclaimed, chain root, another series' UUID) still refused at plan time by the live-binding conditions alone, artifacts byte-untouched. Properties (Hypothesis): - every builder-reachable chain, any country, vintage and entity, keeps one UUID, writes one retire + succeeds pair per hop, passes --check and is byte-idempotent; - in any grammar-admitted history, a live binding its key did not first own was established by succeeds (why the owner conjunct only ever refused chains); - differential: the builder plans an enrichment exactly when UuidRegistry accepts the pair, everything it plans stages and agrees with its catalog, and refusals are plan-time diagnostics. Counterfactually verified: with the owner conjunct restored, both regressions, the chain property and the differential property fail (the differential on 5/5 seeds, shrinking to the dod shape); the stale-row tests pass either way. The mint-path diagnostic now says "already knows (first bound to …)", so test_mint_never_reuses_a_bound_uuid matches that. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Independent review of #360 found a state the live binding misses. A placeholder B hands its lineage to C, then (docket loses and regains its country) takes a fresh UUID back from a coarser placeholder A. B is live and bound to that UUID but still consumed, and the grammar never lets a predecessor hand over twice. Without the dropped owner conjunct the builder planned retire(B) + C succeeds B, which staging then rejected. _plan_enrichment now also requires prior_own_key not in registry.consumed, so it refuses at plan time again (as base did). The review's LOW finding, pre-existing: a docket entry matched to a placeholder through a curated alias keyed the docket row under the alias, so the planned succeeds crossed concepts and died in staging. Enrichment now also requires the prior's concept to equal the canonical one. Observed buckets always take the prior's concept, so only that docket path changes, from a staging failure to a plan-time refusal. Tests: - the review's lifecycle through main (seven events, B live and consumed), refused with and without --allow-remint, artifacts byte-untouched; - the cross-concept docket alias, refused at plan time; - the registry generator gains a "return" move (mint a coarser placeholder and hop it onto a retired key that already handed over), and retired hop targets and consumed rows are weighted up, so the differential property reaches live-but-consumed keys. Counterfactuals: without the consumed check, the lifecycle regression and the differential property fail on 5/5 seeds; without the concept check, the alias regression fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Round-2 review of #360 (LOW L1, L3; NIT N1): - L1 (new in this PR): a docket entry matching a placeholder through a curated alias was refused with the UUID-reuse message, whose remedy (curated alias + --allow-remint) cannot help. - L3 (pre-existing): a placeholder that already handed over once was refused with "superseding UUIDs must be new", blaming a remint nobody made. When the placeholder holds the row's UUID live but either hand-over rule fails, _plan_enrichment now raises a diagnostic naming the cause: lineage never crosses concepts (name the docket entry by the placeholder's own concept), or a placeholder hands over at most once (delete its catalog row and rerun with --allow-remint). Both callers already refused every such row, since the UUID is registered, so only the message changes. Tests exercise each suggested curation: renaming the docket entry enriches cleanly, and deleting the consumed placeholder's row then --allow-remint revives the observed identity's own UUID and retires the placeholder, with --check passing. _event_kind now reads planned events too (absent markers there are None, not missing). N1: the backlog bullet and docstring said the live binding alone is the contract; they now state the hand-over rules too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Delta review of 5be9ff8 (CHANGES; F1 blocking, F2 and F3 non-blocking): the refusal for a placeholder that already handed over prescribed a recipe (delete its catalog row, rerun with --allow-remint) and promised outcomes that do not always hold: - F1: if the returning observation is spelled by a curated alias held only on the placeholder row, deleting the row loses that mapping; the rerun mints a separate alias-named identity and leaves the placeholder live. - F2: an observed identity that is itself consumed reclaims a fresh UUID rather than reviving its retired one. - F3: a returned placeholder can later supersede its UUID while staying consumed, so "holds this uuid as the successor of a later enrichment" can be false. The message now states only the cause: the placeholder already handed a lineage over once and remains consumed, so it cannot hand this one over and the lineage needs explicit curation. Refusal behaviour is unchanged (the review found zero raise-versus-plan differences over 478,632 old/new input pairs). The lifecycle test keeps demonstrating one curation that works for its simple lineage, labelled as such, and the backlog bullet records the caveats instead of a recipe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Review log (durable copies in Round 1: GPT-6.1 Sol, at
Round 2: independent Opus 5.5, at
Round 3: GPT-6.1 Sol delta review of
Fold dependency: #363 is merged ( Round 4: Sol delta review of |
MaxGhenis
marked this pull request as ready for review
October 18, 2026 18:48
Contributor
Author
|
Round 4: GPT-6.1 Sol delta review of
Report: |
4 of 6 tasks
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 fold #363 has merged (
5a6ef17d), and this branch is current with it (f9e0f893). At10bd12e2the full catalog suite passes 235/235 and--checkis current. Review rounds 1–3 and their fixes are logged in the PR comments; round 4 (a Sol delta review of10bd12e2) is running.Why
Thesis resolve run 38962977031 refused
usaspending.dod.prime_award_obligations.fy2026.registered_query_snapshot:The registry history for a2649fd9:
{country, 0100000US, vintage null}. That hop happened when the docket entry gainedcountry: US.The catalog row is still
docket-only. The FY2026 snapshot window closes 2026-10-22._plan_enrichmentrequiredregistry.uuid_owner[row_uuid] == prior_own_key.uuid_ownerrecords the first owner and never moves, so every second enrichment hop was refused, and the row fell through to the UUID-reuse refusal.What
scripts/build_series_catalog.py,_plan_enrichment:uuid_ownerconjunct and its local.prior_own_key not in registry.consumed(review round 1, blocking). A key hands over at most once. A placeholder that handed over and later returned as a later hop's successor is live and bound correctly, but it is still consumed, and the grammar refuses it as a predecessor. Without this check the builder planned a pair that staging rejected; with it, the builder refuses at plan time, as base did.prior["concept"] == canon_key[0](review round 1, LOW, pre-existing). A docket entry matched to a placeholder through a curated alias planned a cross-concept succeeds that died in staging. It now refuses at plan time. Observed buckets always take the prior's concept, so only that docket path changes.row_uuid, and not consumed. These are exactly the retire + succeeds preconditions ofUuidRegistry.tests/test_build_series_catalog.py: 15 new tests.docs/catalog-curation-backlog.md: a dated bullet. The committed ledger is unchanged.Invariants (all executed)
Chain continuity (Hypothesis, through
main).retired+succeedspair handing over the key it retired. No--allow-remint.--checkpasses and a rerun is byte-identical.The owner conjunct only refused chains. In any admitted history, a live binding whose key is not the UUID's first owner was set by a succeeds event.
Plan-time guard ⇔ registry grammar (Hypothesis differential). Take any admitted history, including keys that are live but consumed, plus any docket-only row and any observation.
UuidRegistryaccepts that pair.Stale rows stay refused by the live-binding conditions. Six cases after a chain, each refused with artifacts byte-untouched:
This also covers Enrichment demands the live binding; stale-UUID staging test #153's existing tests.
Regressions:
main;main(B live and consumed → refused, with and without--allow-remint);Intended non-violation: the second hop's retire note still reads "docket placeholder enriched by first observed identity". thesis#362 pins that string.
Verification
pytest tests/test_build_series_catalog.py -qat this head: 233 pass. The 2 failures are the base's own (dd929cbafails them alone; Fold the 2026-10-17 DoD first prints: review fy2026 strips, move the anchor #363 fixes them).9a2bb393): 235 passed.--check: current, 221 series. ruff: clean.dd929cbaplus the synthetic FY2026 dod row:retire(US/vintage-null, a2649fd9)+succeeds(US/current economy, a2649fd9), byte-identical to the diagnosed tail;--checkpasses, and only the dod row changes.Review
adb19015): CHANGES. One blocking finding (live-but-consumed predecessor) and one LOW (cross-concept docket alias). Both are fixed inac8652da, with deterministic regressions and generator coverage for the class.ac8652da): MERGE. Its non-blocking L1, L3 and N1 are fixed in5be9ff8a.5be9ff8a): CHANGES on the consumed-refusal wording. Fixed in10bd12e2, which states only the cause.10bd12e2): running.axiom: n/a: catalog-builder identity bookkeeping, no policy encoding
🤖 Generated with Claude Code