Repository navigation
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>
When a catalog row carried a uuid other than its key's binding, resolve_uuid planned revive + supersede even when the key had retired after handing its lineage over through a succeeds event. The grammar refuses to revive a consumed key, so staging rejected the plan before any write. A docket entry gaining a country reached it by re-keying a geography-free placeholder row onto the handed-over country key (finding L2 of the chronicle#360 round-2 review). The builder now plans a reclaim on the row's uuid, which is new to the registry on that path, as the handed-over branch already did with a fresh uuid. A row whose uuid the registry already knows is refused at plan time with a message naming the cause. The enrichment differential gains a docket call-site arm (alias rows, no-country/US/GB entries, unregistered row uuids), steered so the handed-over class is reached on every seed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Fixes finding L2 from the round-2 independent review of #360 (pre-existing, outside #360's diff).
Bug
resolve_uuid's first branch handles a catalog row whose uuid differs from its key's registry binding (the curator-remint path). It plannedrevive+supersedeeven when the key had retired after handing its lineage over through asucceedsevent. The grammar refuses to revive a consumed key ("revives a consumed lineage — handed-over predecessors are terminal"), so staging rejected the plan before any write. The failure was safe, but the curator got a staging error instead of a valid plan.The reviewer's repro:
mint B(US/null)/U1,retire B,E(US/null, economy) succeeds BBefore this PR the builder planned
revive B+supersede B→U2, and staging rejected both events.Fix
reclaimedevent on the row's uuid. That uuid is new to the registry on this path, which the existing ownership check enforces. This matches the branch below it, which already reclaims a handed-over key on a freshuuid4. Both branches now share_plan_reclaim.--allow-remint, the same as the existing fresh-uuid reclaim.--checkstill fails until the reclaim is written ("identities missing from the registry").UuidRegistrydocstring now lists the reclaim event (it said "five event kinds" and left reclaim out). The backlog doc has a dated entry.Invariants (stated and tested)
For every registry history the grammar admits, and for every existing docket-only row and entry, at both call sites:
build_catalogreturns stages under the full grammar, withmain's ceremony note on gated events, and the staged registry agrees with the catalog: live bindings and rows are in bijection.UuidRegistryadmits that pair.SystemExitcarrying a named diagnostic, and never happens when the grammar admits the hop.Tests
test_a_curated_row_uuid_reclaims_a_handed_over_key: the reviewer's exact repro atbuild_cataloglevel. The plan is exactlyreclaimed B/U2plus E's gated retire, with no revive and no supersede. It stages, B is live on U2 and no longer consumed, U1 stays with E, and agreement holds.test_a_handed_over_key_reclaims_the_row_uuid_through_main: the same move end to end.--checkfails first,mainthen writes exactly the reclaim without--allow-remint,--checkpasses, and a rerun is byte-idempotent.test_a_registered_row_uuid_never_reclaims_a_handed_over_key: the row carries B's own pre-remint uuid. The builder refuses with and without--allow-remintand leaves both artifacts byte-untouched. The named remedy (delete the row) then reclaims on a fresh uuid, and--checkpasses.test_docket_enrichment_is_planned_exactly_when_the_grammar_admits_it(Hypothesis, 400 examples): the docket call-site arm of Let an enriched docket placeholder be enriched again #360's differential, with the same four assertions. It reuses the state-aware_generated_registry. It draws entries with no country, US or GB; rows at any placeholder geography carrying any uuid, including unregistered ones; and rows of another concept that reach the entry only through a curated alias (one draw in five). It also covers reviewer note N2.--hypothesis-show-statistics, seeds 1–3): the handed-over-entry class with an unregistered row uuid (L2) appears in 1.5–4.3% of cases (about 7–23 per run). The same class with a registered uuid appears in 9–10%, and admitted hops in 4.5–6.5% (about 22–35 per run).Evidence
uv run --locked pytest tests/test_build_series_catalog.py -quv run --locked python scripts/build_series_catalog.py --checkcatalog current: 221 seriesuv run --locked ruff check .STAGING-REJECTED hop=False revive=Trueat the docket site. This reproduces the review.The committed ledger never reaches the changed branch:
--checkoutput is unchanged, and so is the catalog.axiom: n/a: catalog builder and registry tooling, with no policy encoding.
🤖 Generated with Claude Code