Skip to content

Roadmap belt foundation: dispatch bindings, focus closure, durable identity, bounded agent report, heal auto-remedy - #7440

Merged
briansrls merged 14 commits into
mainfrom
roadmap-belt-foundation
Jul 29, 2026
Merged

briansrls merged 14 commits into
mainfrom
roadmap-belt-foundation

Conversation

@briansrls

Copy link
Copy Markdown
Contributor

Consolidates #7404, #7418, #7419, #7430 into one branch. Four PRs racing a moving main produced a ROADMAP.md conflict each time it advanced — one branch regenerating the artifact ends that.

1. Dispatch can fire — two nodes bound

Every roadmap node was ExecutionContractUnspecified, so dispatch_environment_admit refused on all of them and nothing below Env had ever executed in production. The frontier hit zero when the 2026-07-27 refresh deleted the node carrying the prior binding, and no claim noticed.

Two bindings, deliberately a pair:

node validation today proves
shell-typed-invocation transport-clean corpus green the Verify path executes
observation-raw-print-retirement emit frontier == 0 (actually 8) red it discriminates

Either alone is a half-claim — a green-only frontier can't distinguish a working verifier from an unconditional one. The red is the ticket's own handback ("the classified zero-residue progress census"), so red→green is the work being finished.

with_execution mirrors the existing sign combinator rather than adding a parameter to seven constructors for a fact holding on two nodes.

2. Focus closed over prerequisites

Owner membership alone rendered pderive-source-slot-binding as ready while its prerequisite in a hidden lane was invisible. Nothing red; the page lied by omission — worse for a dispatched agent than a person.

Visibility is now lane ∪ transitive prerequisite closure, reusing std.graph.graph_reverse_reachable_members. It found five blockers where three were visible by eye — namespace-canonical-binding has its own prerequisites, so the lane was blocked on a namespace sub-chain of three.

The discriminator is a synthetic two-lane fixture, not the live focus: asserting count(pulled) > 0 against roadmap_focus_selection would fail under NoFocus, contradicting the carrier's promise that focus is a one-row view edit.

3. Durable identity as a required field

A node's id was its slug, so a rename was structurally a delete-plus-create. std.occurrence_identity states the right law — identity may not derive from name, span, structure or content hash — but OccurrenceId itself is a per-graph counter from zero: insert a node at the front and everything renumbers; two branches mint the same integer. The law transfers; the type doesn't.

Identity is a required field, not a side registry. That distinction is measurable: adding it produced 50 hard failures (28 literals rejected at compile, 22 call sites at runtime) — every one a place a node could previously exist without identity. A side registry compiles past all fifty.

The index is derived from declared_roadmap_nodes(), so the two can't disagree. Tombstones (ActiveIdentity | TombstonedIdentity{former_slug, superseded_by}) exist because a base-vs-head diff alone can't detect reuse — an identity removed then reused looks exactly like a new one.

4. The agent's report reaches the UI, bounded

The jq projection stripped message content, so an agent_message survived only as an activity classification. The field name is captured, not guessed — codex exec --json against @openai/codex 0.145.0, landed as a version-stamped fixture, because nothing in the repo recorded item.text and the shipped CLI is a stripped binary.

Budget 8192, its own row rather than reusing the 4096 detail budget: a detail is a diagnostic, a report is what an operator reads to judge the work. Truncation is reported, never silent — a report severed mid-sentence and shown as complete is a wrong answer delivered confidently.

5. Heal applies its own remedy

The skew guard printed "merge the base, then re-run" and exited 1 — a correct refusal and a wasted round trip, since the job holds contents: write and already pushes. It's a repair, not a widen: it removes the skew, then re-runs the check it just failed.

A conflict confined to generated artifacts is not a conflict — ROADMAP.md is a pure function of the authority this job rewrites in the next step. Any authored conflict refuses, and classification is on the whole set so mixed never partially resolves.

Validation

  • whole-tree gunbc compile --target dag — EXIT=0, 0 blocking errors
  • ROADMAP.md / ci.yml regenerated from their authorities
  • 199 witnesses green, 0 attributable failures

witness_authority_shows_finish_line_progress fails identically on plain main (2ee7a5c40a8) — verified there before attributing.

Note for review

Three times during this work a bulk operation silently dropped or corrupted content: a --ours resolution discarded the dispatch bindings, a file checkout nearly reverted #7410's recut, and a fixture script collapsed two identities onto one. The last was caught by identities_are_unique_across_the_registry on the first attempt to violate it; the other two were caught only by grepping for each feature after merging.

That asymmetry is why the base-vs-head permanence gate is declared owed rather than quietly dropped — none of the three would have been caught by a witness, and the tombstone carrier here is what makes that gate implementable at all.

🤖 Generated with Claude Code

briansrls and others added 14 commits July 29, 2026 16:17
…sing everywhere

Every roadmap node was ExecutionContractUnspecified, so
dispatch_environment_admit matched that arm and refused before doing anything
else. Clicking Dispatch on any of the ~46 tickets produced a typed refusal and
nothing more, which meant no part of the workflow below Env — worktree, agent,
and every receipt that depends on them — had ever executed end to end in
production. The frontier reached zero when the 2026-07-27 authority refresh
deleted the node that carried the prior binding; no claim noticed, because none
existed.

The binding is a COMBINATOR, not a constructor parameter. `sign` is the
precedent sitting beside it and already threads `execution: rn.execution`
through untouched; threading an execution argument instead would edit seven
constructors and every one of their call sites to express a fact that today
holds for exactly one node. A node without the wrapper keeps
ExecutionContractUnspecified, which stays the fail-closed refusal the frontier
note declares rather than a default anyone chose.

shell-typed-invocation is bound to the transport-clean corpus witness
(corpus_dag_compile_clean_transport_clean_holds), which is this ticket's own red
control expressed as an operation: "a new unclassified production construction
site reds the census". It reads the live tree, so it is a statement about the
repository rather than a fixture.

That validation is ALREADY GREEN, deliberately. A first binding has two jobs
that pull apart — prove the Verify path runs at all, and prove it discriminates
— and conflating them is how a green pipeline gets mistaken for a working one.
This row takes the first job only: an Agent turn that changes nothing still
produces a real admitted environment, a real derived command, and a real
validation receipt, which is a statement about the PLUMBING and not about the
provider. It proves nothing about discrimination and must not be read as
evidence that Verify can fail; the discriminating red belongs on a second node
whose validation is currently red and goes green when the work lands, and that
is the next binding, not this one.

The frontier note is corrected in the same motion. It read "Every node below is
ExecutionContractUnspecified", which was true when written and false the moment
one was bound. It now states the count is one, and that a count is not a
completion.

Three witnesses pin both halves of the frontier: the bound node yields a real
contract rather than the fail-closed variant; the platform/task capability JOIN
actually happens at admission (8 fixed dispatch mechanics + the one capability
this validation derives = 9); and the frontier is exactly one node — which fails
if a binding is silently lost AND if a second is added without updating the
roster, so the documented count cannot drift from the authority.

ROADMAP.md is unchanged: execution contracts are dispatch mechanics, not roadmap
content, and the projection correctly does not render them.

Verified: whole-tree compile 0 blocking errors; 46 witnesses green across
roadmap_authority (incl. the three new ones and the pre-existing re-entry RED
controls), generated_artifact_drift, roadmap_execution_contract, and
roadmap_dispatch_environment.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…n actually fail

The first binding named an already-green validation, on purpose, to prove the
Verify path executes at all — admission, argv derivation, receipt production.
It cannot prove the path DISCRIMINATES, because nothing it runs is capable of
returning anything but green. A frontier with only that binding is the
coverage-by-illusion tier: machinery present, nothing gating on it.

observation-raw-print-retirement now binds a validation that FAILS today.
gunbc.observation_emit_census classifies every seed emit site as exactly one of
MigratedToObservation or CountedFrontierSite, and observation_emit_frontier_count
is the population of the second arm — 8 today (floor-drain, gate-warm-cost,
receipt, file, resolve-split, assembly-split, witness-row-cost,
witness-row-cost-drift). The witness asserts 0, which is that node's handback
stated verbatim: "the classified zero-residue progress census".

So the red is the ticket's own acceptance condition rather than a planted
fixture, the count IS the completion condition rather than a proxy for it, and
red -> green is the work being finished. The two bindings now pin both
directions, and neither claim is obtainable from the other.

Finding a genuine red took some looking, and the search is worth recording: the
transport-script wall is clean corpus-wide (every enrolled path AND every
unenrolled Exec.Run site I measured returns zero violations), so there was no red
available there; the existing known-red quarantine rows are self-host behavioral
receipts that red on cargo/shim closure refusal, which is infrastructure rather
than anything a dispatched agent could turn green. The emit census is the one
place where a small, agent-doable ticket has a countable completion condition
that is currently false.

The acceptance witness is enrolled QuarantineProbeExpectRed in
gunbc.ci_layer_roots — the cadence std.witness_admission defines for exactly
this, "known-red quarantined rows run on a probe cadence expecting red (greening
is a counted un-quarantine event)" — so a deliberately-red acceptance test does
not red the corpus. Its dissolution is forced rather than optional: when the
frontier reaches zero the roster row becomes a still-red expectation against a
green witness, so it must be deleted in the same change that lands the last
migration, promoting the witness to ordinary DiscoverySelection as a standing
regression ratchet.

It lives in its own file rather than inside observation_emit_census_witness_test
because that suite asserts the count the census HAS (== 8, which must red if the
roster drifts) while this asserts the count the work OWES (== 0). Both are true
and they disagree by construction; merging them would drag the roster's own
hygiene check into quarantine and stop it reding when it should.

The frontier note now reads TWO and says why the pair is one claim rather than
two bindings. witness_execution_contract_frontier_is_exactly_one_node becomes
_two_nodes, joined by witness_bound_pair_covers_both_verify_directions.

Verified: whole-tree compile 0 blocking errors; the discriminating validation
FAILS and the plumbing validation PASSES when each is run directly, which is the
receipt that matters; 63 witnesses green with zero failures across
roadmap_authority, generated_artifact_drift, observation_emit_census and
witness_admission.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ion reported

The dashboard could not show what an agent actually said. The raw JSONL is
retained per attempt, but codex_provider_event_projection_filter — the jq stage
that bounds each line before the substrate reads it — emitted only
{"type":…,"item":{"type":…}} for item events, so an agent_message survived as an
activity CLASSIFICATION and its text was gone before anything could render it.
That was deliberate: the boundary exists because one item.completed carrying
~154KB of aggregated command output killed the old 64KB reader. So surfacing the
report is a change AT that boundary, not a rendering change, and the reviewable
decision is the bound.

THE FIELD NAME IS CAPTURED, NOT GUESSED. Nothing in the repository recorded the
agent_message item's text member, the shipped CLI is a stripped native binary,
and the locator extdeps.llm.cli already cites documents the mode rather than the
per-item event schema. Modeling it from memory is the guess DESIGN §3 forbids for
an extdeps surface, and #7368's own design note sets the same bar for provider
grammars: admitted only "after an actual provider receipt demonstrates its
grammar". So a receipt was produced — codex exec --json against @openai/codex
0.145.0, landed under dag/test/fixture/codex_provider_events with its version and
capture conditions. Its third line is the authority:

  {"type":"item.completed","item":{"id":"item_0","type":"agent_message","text":"ok"}}

The report gets its OWN budget rather than reusing the detail budget beside it.
They are the same type and genuinely different facts: a detail is a diagnostic,
short by nature, read to find out what broke; a report is what the provider says
it DID, and it is the text an operator reads to judge whether the work is any
good. One shared number would mean tuning either bound silently retunes the
other. 8192 is set against the incident this projection exists to prevent — an
order of magnitude under the 65536 line budget so a report can never be the
payload that reproduces it, and deliberately above the 4096 detail budget because
a 4KB error is pathological while a 6KB work summary is ordinary.

TRUNCATION IS REPORTED, NEVER SILENT. Everywhere else these bounds guard a
machine-read classification, where a cut string simply fails to match and
refuses. Here the bounded value is prose an operator reads and acts on, so a
report severed mid-sentence and shown as if complete is a wrong answer delivered
confidently — the operator would judge the work on a fragment with nothing on
screen saying so. The envelope therefore carries a message object pairing the
bounded text with a truncated flag computed from the ORIGINAL length before
slicing, so the flag describes the provider's output rather than the slice.

The anchored item.type walk is untouched by construction: the report is emitted
as a member AFTER item.type, so item.type remains item's first member and the
walk's landing position is unchanged — a report whose own text quotes an
item-type fragment still cannot reclassify the pane. The note that described the
envelope shape is corrected to say so rather than understating it.

Verified by execution, which for a jq program means running the MODELED filter
string rather than a hand copy: extracted from the substrate and run through real
jq against the real captured receipt, it yields
{"text":"ok","truncated":false}; against an 8193-character control it yields
exactly 8192 retained characters and truncated:true.

Four witnesses pin the contract the shell cannot prove downstream: the bound is
the message budget (a copy-paste of the detail budget would still emit valid jq
and still look fine until the day a long message arrived), the two budgets are
distinct, truncation is computed against the original length, and both item
envelope shapes keep item.type first.

Verified: whole-tree compile 0 blocking errors; provider-events 18/18; 50 more
green across roadmap_workflow_progress, generated_artifact_drift and
roadmap_authority; zero failures.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…tity

Two roadmap-authority changes, both about replanning not destroying work.

FOCUS CLOSURE. Owner membership alone was the wrong visibility rule. The v1
deletion lane's critical path runs through pderive-source-slot-binding, whose
prerequisite namespace-canonical-binding lives in a lane the focus hid — so the
page rendered the fourth link of the spine as ready with its blocker invisible.
Nothing was red; the page lied by omission. Worse for a dispatched agent than for
a person: a worker reads a ready-looking node, starts, and stalls on work the
roadmap never mentioned.

Visibility is now lane membership UNION the transitive prerequisite closure,
reusing std.graph.graph_reverse_reachable_members over the roadmap's own edge
relation rather than minting a second walk — the edge is already a dependency
edge, reverse reachability from a lane node is exactly its ancestors, and the
graph is acyclic by witness so the walk terminates by construction. The closure
found FIVE blockers, not the three visible by eye: namespace-canonical-binding
has its own prerequisites, so the lane was blocked on a namespace sub-chain of
three. Manual inspection would have discovered those one stall at a time.

Pulled-in rows are named as prerequisites rather than counted as lane work, so
the lane's real size stays honest at 17. The focus label is now "the v1 deletion
lane" per the operator's naming.

DURABLE IDENTITY. A roadmap node's id is its authored slug
(RoadmapNodeId = NonEmptyStr), so a rename is structurally a delete plus a
create: edges stop resolving, receipts name a node that no longer exists, and any
attempt or session joined to it is orphaned. That is not hypothetical — the
2026-07-27 authority refresh deleted the node carrying the only execution
contract and no claim noticed.

std.occurrence_identity already states the right law: identity may not derive
from filename, span, authored name, structural equality, or content hash. The LAW
is reused; the TYPE deliberately is not. OccurrenceId is an ordinal from a
per-graph allocator starting at zero, so inserting a node at the front renumbers
every node after it and two branches mint the same integer — positional identity
wearing an allocator's clothes. Correct for occurrences inside one parse, wrong
for an entity that must survive edits, reordering, regeneration and independent
branches. What occurrence identity does not claim is PERSISTENCE SCOPE, and that
is the only thing missing.

51 collision-resistant identities are minted and persisted, one per declared
node, at AUTHORING time — nothing mints during render, compile or regen, because
a value re-derivable by evaluation would reintroduce the property the module
exists to remove. The slug stays readable and stops being identity.

Stage I0 is deliberately additive: no rendering, dependency, receipt or dispatch
path changes. The v1-deletion recut can be authored against durable identities
immediately without waiting on a consumer migration, and without its new nodes
being rewritten a second time afterwards.

TWO GATES DECLARED AS OWED, NOT ASSUMED. Permanence is a historical property and
every witness here reads the current tree, so an identity silently REPLACED
between base and head satisfies all of them — the snapshot corpus is structurally
incapable of catching the exact edit this module forbids. The owed row lists the
admitted and refused transitions for a base-versus-head registry comparison.
Separately, decomposition needs an explicit parent completion policy: containment
keeps pointers valid but cannot say whether a parent completes on direct
acceptance, on all children, or both, and inferring it would silently close a
parent whose children are unfinished.

Verified: whole-tree compile 0 blocking errors; ROADMAP.md regenerated; 109
witnesses green with zero failures across roadmap_identity (7, incl. the
discriminating identity_is_persisted_not_positional), roadmap_focus (8, incl.
no_visible_node_has_a_hidden_prerequisite), roadmap_authority,
generated_artifact_drift, roadmap_page, doc_reachability (both homes),
roadmap_emit and roadmap_document.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…inting it

The skew guard printed "merge the base branch, then re-run" and exited 1. That is
a correct refusal and a wasted round trip: the job holds contents:write, already
pushes commits to this branch, and the fix is a merge it is fully authorized to
perform. Making a human do a mechanical repair the machine can do is the toil
this pipeline exists to remove (operator ruling 2026-07-29).

This is a REPAIR, not a widen, which is what makes it admissible under DESIGN §5.
The arm does not proceed despite the skew — it REMOVES the skew by merging the
base into the branch, then re-runs the same check it just failed. Regeneration
happens only if that second check passes, so artifacts are still projected by a
compiler the tree agrees with. The invariant is re-established and re-verified,
never assumed. The remedy is attempted exactly once; a base that moves again
mid-run refuses rather than looping.

A MERGE CONFLICT CONFINED TO GENERATED ARTIFACTS IS NOT A CONFLICT. Measured on
the first real skew this guard caught (#7404): the only conflicting path was
ROADMAP.md — a registered generated artifact this job rewrites from its authority
in the very next step. Two branches that both regenerate a projection will always
collide in the projection, so refusing there would fail the auto-remedy on its
single most common case while the authorities underneath merged cleanly.

A generated artifact has no independent content to reconcile: it is a pure
function of the .dag authority, so whichever side is checked out is equally wrong
until main_wet runs and equally right afterwards. Taking either side and
regenerating is not a guess — the bytes are determined by the merged authority,
and the drift gate proves the result is that authority's fixed point. Scope is
exactly committed_generated_artifact_paths(), the same registry the staging step
uses, so a file qualifies only by being declared generated.

Both failure arms stay closed. If ANY conflicting path is outside that registry
the merge aborts and refuses, listing every conflict and naming the authored ones
— the classification is on the WHOLE set, so one authored conflict refuses the
entire remedy rather than partially resolving into a half-merged tree.

The merge commit is --no-verify: this is an unattended machine commit, and the
repository's own rulings already establish that git hooks are per-clone developer
feedback rather than enforcement (opt-in via core.hooksPath, bypassable, absent
in container worktrees). Found by execution — the local pre-commit hook failed
the remedy's commit with a cargo-not-on-PATH error, which CI would not have hit
but which should not gate a machine commit in any case.

Verified by execution against the real #7404 skew, not a fixture: skew detected,
merge attempted, conflict correctly classified as generated-only, resolved,
re-checked, EXIT=0 with the seed skew gone. The classification arm is unit-tested
across five cases — generated-only and generated x2 auto-resolve; authored-only,
seed-Rust, and MIXED all refuse, the mixed case being the one that must not
partially resolve.

Verified: whole-tree compile 0 blocking errors; ci.yml regenerated from the
model; emitted guard bash -n clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Owner membership alone was the wrong visibility rule. The v1 deletion lane's
critical path runs through pderive-source-slot-binding, whose prerequisite
namespace-canonical-binding lives in a lane the focus hid — so the page rendered
the fourth link of the spine as READY with its blocker invisible. Nothing was
red; the page lied by omission. That is worse for a dispatched agent than for a
person: a worker reads a ready-looking node, starts, and stalls on work the
roadmap never mentioned.

Visibility is now lane membership UNION the transitive prerequisite closure,
reusing std.graph.graph_reverse_reachable_members over the roadmap's own edge
relation rather than minting a second walk — the edge is already a dependency
edge, reverse reachability from a lane node is exactly its ancestors, and the
graph is acyclic by witness so the walk terminates by construction.

The closure found FIVE blockers where three were visible by eye:
namespace-canonical-binding has its own prerequisites, so the lane was blocked on
a namespace sub-chain of three. Manual inspection would have found those one
stall at a time, each costing a wasted attempt.

Pulled-in rows are named as prerequisites in the notice rather than counted as
lane work, so the lane's real size stays honest.

THE DISCRIMINATOR IS SYNTHETIC, deliberately (review). An earlier cut asserted
count(pulled) > 0 against the live roadmap_focus_selection, which contradicts the
carrier's own promise that changing or clearing the focus is a one-row view edit:
it fails the moment the focus is NoFocus, or a lane that legitimately has no
cross-owner prerequisite — reporting a defect where none exists and making the
focus row un-editable in practice. The fixture owns its two lanes and its
transitive cross-lane chain, so it holds under any live focus, and it exercises
TRANSITIVITY (b3 pulls b2 pulls b1) which is the part manual inspection misses.
A companion asserts the no-external-prerequisite case pulls nothing, so the empty
result is a tested outcome rather than an untested branch.

The notice claim is also strengthened per review: the test named
"pulled in and named as such" now actually checks the notice contains every
pulled id, which it previously did not.

The live-tree invariant is stated conditionally beside the fixture: whatever the
current focus is, no visible node may have a hidden prerequisite. That holds
under every focus including NoFocus, so it constrains the projection without
pinning the selection.

Split out of #7417 on review: the identity half needs identity on RoadmapNode, an
active/tombstoned lifecycle, and a base-versus-head permanence gate, and is being
rebuilt separately. This half is independent of that work.

Verified: whole-tree compile 0 blocking errors; ROADMAP.md regenerated from the
authority; 104 witnesses green with zero failures across roadmap_focus (12),
roadmap_authority, generated_artifact_drift, roadmap_page, doc_reachability (both
homes), roadmap_emit and roadmap_document.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A roadmap node's id was its authored slug, so a rename was structurally a delete
plus a create: edges stop resolving, acceptance receipts name a node that no
longer exists, and any attempt or session joined to it is orphaned. Not
hypothetical — the 2026-07-27 authority refresh deleted the node carrying the
only execution contract and no claim noticed.

std.occurrence_identity already states the right law: identity may not derive
from filename, span, authored name, structural equality or content hash. The LAW
is reused; the TYPE deliberately is not. OccurrenceId is an ordinal from a
per-graph allocator starting at zero, so inserting a node at the front renumbers
everything after it and two branches mint the same integer — positional identity
wearing an allocator's clothes. Right for occurrences inside one parse, wrong for
an entity that must survive edits, reordering, regeneration and independent
branches. What occurrence identity does not claim is PERSISTENCE SCOPE, and that
is the only thing missing.

IDENTITY IS A REQUIRED FIELD, NOT A SIDE REGISTRY. The first cut carried a
hand-written (identity, slug) list beside the authority. It compiled cleanly and
was wrong twice over: two authorities that must be kept in step (DESIGN 3), and a
node still authorable WITHOUT an identity, detectable only by a later witness —
validation standing where construction was available (DESIGN 5). As a field it is
unwritable instead, and the index is DERIVED from declared_roadmap_nodes() so the
two cannot disagree.

The change measured its own necessity: adding the field produced 50 hard failures
— 28 struct literals the compiler rejected outright, then 22 constructor call
sites failing with `undefined variable: identity`. Every one was a site where a
node could previously come into existence without durable identity, and the side
registry would have compiled past all fifty.

62 collision-resistant identities are minted and persisted at AUTHORING time.
Nothing mints during render, compile or regen; a value re-derivable by evaluation
would reintroduce the property this exists to remove.

TOMBSTONES, because a base-versus-head diff alone cannot enforce non-reuse.
Without persisted retirement: PR A removes node X, a diff observes the removal
once, after merge X is simply absent from base, PR B reuses X's identity, and the
next comparison sees present-in-head/absent-in-base — indistinguishable from a
legitimately new identity. The reuse passes every check. So retirement is a STATE:
TombstonedIdentity keeps the identity forever, carries the slug it last wore so
historical links resolve, and names its successor. The roster is empty today and
the witnesses are arithmetic (registry == active + tombstoned) rather than
pinning zero, so the first real retirement will not red them.

RESOLUTION IS EXACTLY-ONE. filter-map-first answers a duplicate registry with a
plausible first row — the fabricated-plausible-output arm DESIGN 5 forbids, and
it fails exactly when the registry is corrupt and a confident wrong answer is
worst. IdentityResolved | IdentityUnknown | IdentityAmbiguous{matches} keeps the
three remedies distinct.

The discriminating witness is identity_survives_a_slug_rename. Every other claim
here — uniqueness, totality, resolution — is equally true of a broken registry
where identity IS the slug; only this one fails if the separation collapses.

STILL OWED: the permanence gate. Every claim reads the current tree, so an
identity silently REPLACED between base and head satisfies all of them. The
carrier lists the admitted and refused transitions concretely; the tombstone
above is what makes that gate implementable at all.

ROADMAP.md is unchanged: identity is machinery, the slug remains display.

Verified: whole-tree compile EXIT=0, 0 blocking errors; ROADMAP.md regenerated;
241 witnesses green across 15 roadmap suites. Seven wet witnesses fail
identically on plain main (hermetic mode refusing to fabricate a host Check) and
are unrelated — confirmed by running them on origin/main before attributing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CI caught orphaned enrollment, which is the Phase 0(b) admission invariant
working exactly as intended:

  WITNESS ADMISSION REFUSAL cause=UnexecutedDeferredWitness count=1 —
  enrolled witness row(s) excluded from discovery name zero executing consumers

The deliberately-red acceptance witness was classified QuarantineProbeExpectRed
in witness_exclusion_frontier, which removes it from per-PR discovery. That is
half the job. The exclusion says where it does NOT run; it does not say where it
DOES. Without a matching row on known_red_probe_entries — the roster that
actually executes known-red witnesses on their probe cadence expecting red —
the witness ran nowhere, which is precisely the "enrolled, zero executions"
coverage-by-illusion the invariant refuses.

Adding the probe row completes the pair. The exclusion note now states the
pairing rule and cites this failure, so the next author reads why both rows are
required rather than discovering it from a floor red.

Verified: whole-tree compile 0 blocking errors; ci.yml/ROADMAP.md regenerated.
…map-belt-foundation

# Conflicts:
#	ROADMAP.md
…to roadmap-belt-foundation

# Conflicts:
#	ROADMAP.md
#	dag/gunbc/roadmap_authority.dag
#	dag/gunbc/roadmap_identity.dag
#	dag/test/claim/roadmap_focus_witness_test.dag
#	dag/test/claim/roadmap_identity_witness_test.dag
The fixture-identity script matched the RoadmapNode literal inside
with_execution and replaced its `identity: rn.identity` pass-through with a
hardcoded literal. Since with_execution wraps both bound nodes, both collapsed
onto one identity.

identities_are_unique_across_the_registry failed on the first attempt to violate
it — which is the claim's whole purpose: it is the one that notices when identity
stops being per-node. Caught before the change could ship rather than after.

Both combinators (sign, with_execution) now thread rn.identity. Verified: 4/4
identity witnesses green including identity_survives_a_slug_rename.
@cursor

cursor Bot commented Jul 29, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

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