Skip to content

Pin the identity anchor in a fixture and re-derive machine moves - #372

Merged
MaxGhenis merged 8 commits into
codex/thesis-ledger-factsfrom
fix/identity-anchor-fixture
Oct 20, 2026
Merged

MaxGhenis merged 8 commits into
codex/thesis-ledger-factsfrom
fix/identity-anchor-fixture

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

This is the Chronicle half of the fix for resolver appends merging past a red required "Arch checks". The Thesis half is ThesisInstitute/thesis#377: the resolver writes provable curation into its own proposals and awaits Arch checks. Land this PR first; until it lands, #377 cannot move the anchor and reports it as curation still needed.

Why

The Thesis resolver's admin token merges on two checks, Append gate and Trusted base append gate. Branch protection on codex/thesis-ledger-facts also requires Arch checks, but enforce_admins is off, so nothing stops the merge. I went through all 28 resolver append PRs (07-10 to 10-19):

Since the August catalog fix, every one of these failures came from two curation tests:

  • the period-strip audit;
  • test_identity_uuid_map_matches_reviewed_anchor.

The anchor moves on every first observation that enriches a docket placeholder or mints an identity. It lived as a literal in the test, so only a hand-edited curation PR could move it (#363, #371). It also cannot move before the rows exist, because it pins the post-append digest.

What

  • tests/fixtures/series_catalog/identity_anchor.json holds the pin, unchanged at d5b88530…, and a move field.
  • move: null means a curator pinned it, as before, with a dated entry in the test's comment history.
  • A machine move records by, run_url, from_sha256 and events. Each event is a mint or an enrich with its placeholder_geography.
  • build_series_catalog.identity_anchor_problems re-derives from_sha256 from the current catalog and the recorded events. It accepts only:
    • mints of full identities under UUIDs the prior catalog does not hold;
    • enrichments of entity-free placeholders under the same UUID and concept, where the placeholder's geography admits the new one (the same rule as _plan_enrichment).
  • Relative to from_sha256, anything else is reported: a remint, supersede, retire, entity change on a full identity, unrecorded change or unsorted events.
  • from_sha256 itself is tied to the base. The test sees only the current catalog, so a self-consistent record with a false origin would pass it. A new Arch checks step, "Identity anchor move continues the base pin", runs identity_anchor_continuity_problems against the same comparison base as the registry append-only step. It requires a move that changes the pin to start from the base's pin, and refuses a mint whose UUID the base registry already holds (bringing a retired UUID back is a revive, a curator's call).

Invariants (property-tested)

Review round 1 (in-session Opus)

  • Fixed: the forged-origin gap above (P2), and a non-string event kind now produces a problem instead of raising.
  • New tests: the review's forged-origin case, a property that a move continues the base exactly when it starts from the base's pin, the CLI, and malformed kinds.

Review round 2 (hard tier, served by Opus 5.5)

  • P3-1: a machine move over a catalog that repeats a row or a UUID is now reported. The digest covers the list with its duplicates, while the undo works on sets.
  • P3-2: a mint that repeats an identity the prior catalog already binds is reported.
  • P3-8:
    • The continuity step leaves a new branch's first push to its pull-request run. Such a push has no comparison base of its own, and a branch cut before the latest machine move would compare an older move with today's pin.
    • The CLI treats a missing anchor fixture as nothing to check.
    • thesis#377 now requires both Arch checks runs under its "refuse" policy, so a skipped push run can't stand in for the pull-request check.
  • P3-11: the soundness property is parametrized over its 13 mutations, so a mutation Hypothesis can never exercise fails. The append generator binds each identity once, as a real catalog does.

Review round 3 (hard tier, Opus 5.5)

  • P3-B: two mints of one identity in a single move, or a placeholder enriched onto an identity already bound, used to pass the mint-collision check. A machine move now requires every identity in the current catalog to be bound once. Real catalogs meet this: 221 rows and 221 identities at every commit checked. Two new parametrized mutations cover these cases, and each fails without the check.

Review rounds 4 and 5 (hard tier, Opus 5.5): APPROVE WITH NITS

The mint-reuse and mint-collision checks are marked defensive, since the uniqueness rule makes them unreachable. Round 5 confirmed this at ad7f54c, with no P1 or P2.

Verification

  • Local, targeted (disk pause Add state IRS SOI source packages #9, so no full suite here): the new tests, test_doctests_pass, test_committed_catalog_is_current_and_valid and the fixture well-formedness test pass (7 passed). The full file runs in Arch checks on this PR.
  • ruff: no new findings against the base.

No ledger bytes change.

🤖 Generated with Claude Code

The identity anchor lived as a literal in
test_identity_uuid_map_matches_reviewed_anchor, so only a hand edit of the
test could move it. Every first observation that enriches a docket
placeholder or mints an identity moves it, so each such resolver append
(chronicle#361, #369) merged with Arch checks red and held every other
pull request into this branch until a curation PR (#363, #371) moved the
literal by hand.

The pin now lives in tests/fixtures/series_catalog/identity_anchor.json,
unchanged (d5b88530...). A curator still moves it with move null and a
dated entry in the test's history. A machine may also move it, recording
from_sha256 and one event per identity tuple it changed;
build_series_catalog.identity_anchor_problems re-derives from_sha256 from
the current catalog and those events and accepts only mints of full
identities under fresh UUIDs and enrichments of entity-free placeholders
under the same UUID and concept. A remint, supersede, retire, entity change
on a full identity or any unrecorded change is reported.

Property tests: any sanctioned append recorded as a move is accepted, and
each of eleven ways a move can misstate its append is reported.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 6 commits October 19, 2026 13:35
Review round 1 (in-session Opus) showed identity_anchor_problems accepts a
self-consistent record with a false origin: remint (u_old, a) as (u_new, a),
record "mint u_new" with from_sha256 = the current catalog minus u_new, and
the record re-derives cleanly. The function only sees the current catalog,
so it cannot know where the branch was.

identity_anchor_continuity_problems requires a move that changes the pin to
start from the base commit's pin, and refuses a mint whose UUID the base
registry already holds (a revive is a curator's call). A new Arch checks
step, "Identity anchor move continues the base pin", runs it against the
same comparison base as the registry append-only step. The fixture comment
and docstring now say exactly what each check proves.

Also: a non-string event kind is reported instead of raising TypeError.

Tests: the review's forged-origin case, a property that a move continues
the base exactly when it starts from the base's pin, the CLI, and
malformed kinds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 2 (hard tier, served by Opus 5.5 with the Codex lanes held):

- P3-1: the digest covers the catalog's tuples as a list, duplicates
  included, while identity_anchor_problems undoes events on sets, so a
  repeated row or a UUID on two rows could hide a change. A machine move
  over such a catalog is now reported.
- P3-2: a mint that repeats an identity the prior catalog already binds
  (the same concept, geography and entity under a second UUID) is
  reported.
- P3-8: the continuity step leaves a new branch's first push to its pull
  request run (no comparison base of its own; a branch cut before the
  latest machine move would compare an older move with today's pin), and
  the CLI treats a missing identity anchor fixture as nothing to check.
- P3-11: the soundness property is parametrized over its 13 mutations, so
  one Hypothesis can never exercise fails; the append generator binds each
  identity once, as a real catalog does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 3 (hard tier, Opus 5.5), P3-B: two mints of one identity in
one move, or a placeholder enriched onto an identity another row already
binds, left the prior catalog's identities untouched and so passed the
mint-collision check. A machine move now requires every identity in the
current catalog to be bound once (real catalogs are: 221 rows, 221
identities at every commit checked). Two new parametrized mutations cover
both cases; each fails without the check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 4 nit: with rows, UUIDs and identities unique in the current
catalog, the mint-reuse and mint-collision checks cannot fire; they stay
as a guard in case the uniqueness rule is ever relaxed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis merged commit 5f39821 into codex/thesis-ledger-facts Oct 20, 2026
8 checks passed
@MaxGhenis
MaxGhenis deleted the fix/identity-anchor-fixture branch October 20, 2026 18:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant