Skip to content

Give the proposal vocabulary its own authority and stop one spelling carrying two contracts - #10355

Merged
briansrls merged 12 commits into
mainfrom
scm-role-requirement-integration-cut
Sep 4, 2026
Merged

briansrls merged 12 commits into
mainfrom
scm-role-requirement-integration-cut

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor

What this is

Two things, and they are not the same claim:

  • the role-requirement integration operation preserves its behavior — this half is a
    behavior-preserving authority migration;
  • the namespace-admission roster intentionally changes, to admit this transition and retire
    rows consumed by their own merge. That is a deliberate behavior change in a gate, not a no-op.

What the earlier description got wrong, and what it got right

An earlier version of this description called the change "semantically a no-op" and reported
"83 cells", "five affected witness modules", "67 cells" and "all nine touched modules". A later
version over-corrected by withdrawing all of it. The accurate account:

statement verdict
"semantically a no-op" false. Production behaviour of the operation is unchanged, but claim identity is program data and it changed; the roster change is a real gate change
total "83" false. No population has this size
"all nine touched modules" false. It corresponded to no command and no population
"five affected witness modules" correct, and still correct. It is the exact population in the evidence table below
the "67"-claim run correct as far as it went. A valid three-module subset — 5 + 43 + 19 — but not branch-wide evidence, which is the distinction it failed to state

Withdrawing the two true statements along with the three false ones was itself an error: an
over-broad retraction destroys a correct measurement just as a false claim does.

The two moves

  1. gunbc.scm.proposal is extracted as its own authority (new module). It owns the proposal
    nouns — Requirement, RequireBinding, RequireBindingAbsent, requirement_role, Proposal,
    RoleDependency — and deliberately does not depend on ObjectStore or ObjectId. The nouns and
    the operation over them were one module answering two questions.

  2. gunbc.scm.merge becomes gunbc.scm.role_requirement_integration. The old spelling was a
    §3 meaning fork: merge named roles / requirements / supersession, while the same word is
    owed to two-commit merging, which this kernel does not do and which gunbc.scm.ancestry
    is the subject of. One spelling was carrying two contracts. Every type, constructor, function
    and executable tag follows the module.

MergeDependencyKind is deliberately not renamed: it is a historical symbol, and rewriting it
would have fabricated a name that never existed. An earlier commit on this branch did exactly that;
it is restored.

Claim identity census — the complete population

Renaming a module re-qualifies every claim it declares, not only the ones whose local name
changed. The full migration is 20 claim-identity migrations — 20 removed identities and 20 added
identities
, i.e. 20 declarations whose fully qualified identity changed. (Stating it as "20 claim
identities" was the wrong grain: each transition removes one identity and adds another, so the
symmetric difference holds 40 distinct identity values. The checks below are organised over the 20
old-to-new mappings, which is the right unit for them.)

population count old → new
declared in the renamed module, local name unchanged 15 test.claim.scm_merge_witness.<n> → test.claim.scm_role_requirement_integration_witness.<n>
declared in the renamed module, local name also changed 4 merge_a_role_whose_value_is_a_file_refuses_as_authored_source → integrating_a_role_…; merge_a_role_whose_value_is_a_node_merges → integrating_a_role_whose_value_is_a_node_integrates; merge_a_target_root_that_is_a_file_refuses_as_authored_source → integrating_over_a_target_root_…; merge_a_target_root_that_is_a_node_does_not_refuse → integrating_over_a_target_root_that_is_a_node_does_not_refuse
declared in test.claim.scm_commit_closure_json_v2_witness (module identity unchanged), local name changed 1 scm_image_a_role_whose_value_is_a_node_merges → scm_image_a_role_whose_value_is_a_node_integrates

Checked against that population, not against the four renamed locals:

  • External citations. Five of the 19 are cited in docs/plans/dag-native-scm-design.md. None of
    the five is among the four that changed local name, and the document's own module references were
    swept to the new identity. git grep scm_merge_witness returns empty across the tree.
  • Rosters / workflow enrollment / coverage joins. The only files naming this module identity are
    the three SCM witness modules and that design document; no workflow YAML, roster or coverage join
    enrolls it by name, so the re-qualification has no enrollment consequence to migrate.

While verifying the coverage join I found a transcribed count that had rotted: the design
document said "the 15 claims in test.claim.…" while the module declares 19. It was correct when
#8794 wrote it and has been wrong since.

The two sites carrying that count were repaired differently, because they are different subjects.
An earlier version of this section said both now name the module so the population is "re-derived
rather than remembered". That was true of the first repair and is not true on this head:

  • the ordinary witnesses-are-not-consumers sentence names the current module without transcribing
    a cardinality — it needs none;
  • the dated 4 of 13 coverage receipt does not point at the current module as an instrument.
    Doing that was the error: naming a renamed module made an August measurement look re-derived when
    nothing re-derived it. It is now historicized to the claim population that existed on 2026-08-21,
    is explicitly not a current-completeness claim, and the document states that no current-head join
    has re-derived it.

Scope

14 changed files: 11 .dag modules, 2 Markdown documents, and 1 Rust file —
src/v1/stage0/src/namespace_wave_admission.rs, the namespace-admission roster that makes this
transition admissible. An earlier version of this section said "11 .dag modules and two Markdown
files" and omitted the Rust file, which is the one that changes gate behaviour.

There is no "nine"; that figure in the withdrawn description corresponded to no command and no
population.

Evidence

Instrument: target/release/claim_batch --source-root dag --source-root src/v2 --entry <module> --functions <every test fn the module declares>, run once per module because --functions is scoped to the entry.

All five witness modules the branch touches were run at head 01a98bf — clean worktree at that
exact commit — and every one exited 0, 82 claims total:

module claims
scm_authoring 5
scm_checkout_verb 8
scm_commit_closure_json_v2 43
scm_role_requirement_integration 19
scm_status 7

Earlier measurements on this branch (4bb1aba, 8a75218, a749a43, af0a561, 3c6e095) were real when
taken and are superseded, not withdrawn. Each stopped governing when a subsequent merge of
origin/main changed the measured corpus or the admission roster. af0a561 in particular reached
terminal CI success on every required job — workflow 33861883243 — before #10358 forced the
merge that produced this head. That result is parent-head causal evidence, not exact-head
admission, and this branch has now been shown twice that the distinction is not pedantry: the two
merges since have each changed the roster's contents.

This description does not state CI status, deliberately. Any tense-bearing claim about CI in a
mutable body rots twice over: "pending" becomes false when the run completes, and "green" becomes
false when the head moves — both of which have now happened on this branch. Per DESIGN §6 the
instrument is named rather than its output transcribed: CI state for the current head is the
checks list on this PR
, which is authoritative and updates itself.

What is stable, because each is bound to a named commit rather than to "now", is the claim-run
table above and the superseded-run note below it.

Run locally, not on BuildBuddy: the remote runner exposes no cgroup memory.high/memory.max, so
claim_batch refuses with HostBudgetUnreadable rather than planning against a machine-wide
number, and GUNBC_* is deliberately not forwarded to remote. CI runs it where the limit binds.

Also clean at this head: cargo fmt --all --check, and zero indented // in .dag (the DESIGN
section 4c module-item-grain proxy) both in the changed files and tree-wide.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VQ4iThiZ1B9LPB9ePr8qa9

…carrying two contracts

gunbc.scm.merge answered a bounded question -- one target commit plus N authored
proposals, folded at role grain into one resulting root -- but it held the name
"merge". Two-commit merge is a materially different contract: two commit
occurrences and a derived common base, a different failure population, a
different output meaning. Section 3 says a materially different contract needs a
materially different name, and a second operation called merge was about to
arrive. This cuts the existing authority over BEFORE that happens rather than
after, because the fork is cheap to remove while it is still latent.

THE MODULE WAS ALSO THE ACCIDENTAL HOME OF ITS OWN INPUTS, and that was measured
rather than asserted. Of the eight modules importing gunbc.scm.merge, SIX
consumed only the proposal nouns and never the operation -- and three of those
six are production modules (gunbc.scm.status, gunbc.scm.authoring,
gunbc.scm.read_command). Only the two witness modules consumed the operation. A
vocabulary with three times the consumers of the operation it was filed under is
not a detail of that operation.

  gunbc.scm.proposal                      Requirement, RequireBinding,
                                          RequireBindingAbsent, requirement_role,
                                          Proposal, RoleDependency
  gunbc.scm.role_requirement_integration  everything else, with the outcome
                                          renamed off "Merge" through to the
                                          externally meaningful result

DesiredRoleValue STAYS WITH THE OPERATION, which corrects my own first partition.
I had placed it with the nouns on the reasoning that a contested alternative is
authored intent. The module's own annotation says otherwise and I had read past
it: a Requirement is authored syntax, a RoleValue is result provenance, and
DesiredRoleValue is the REQUESTED STATE that both normalize into -- produced by
normalize_requirement, which does object-store work and can refuse with a locator
collision. Derived from authored intent is not the same fact as authored intent;
a proposer cannot write one. Keeping it operation-side also keeps ObjectStore and
ObjectId out of the noun layer, so the dependency direction is proposal nouns ->
integration -> object store, never back.

RoleDependency, NOT ProposalDependency. The integration consumes this carrier in
TWO populations -- the target's own dependencies and the ones a proposal declares
-- and combines them in effective_dependencies, so a proposal-flavoured name
would make every target-side use a lie. It is named for the relation. Which
kinds an integration supports, which propagate a removal, and how an unsupported
kind refuses stay with the operation: that is classifier policy, not a property
of the row.

RESIDUE THIS DOES NOT CLOSE, recorded on the carrier rather than left silent:
target and target_dependencies still arrive as independent arguments and nothing
proves the second was derived from the first, so a foreign or empty population
can admit an invalid removal or fabricate a refusal. That is gunbc#10295's
subject-binding class at role-dependency grain. Moving the carrier to its right
home does NOT bind the population, and the annotation says so explicitly with a
next-rung trigger naming the capability.

PROSE MOVED WITH THE SYMBOLS. A rename that leaves notes pointing at the deleted
module is the evidence-bearing-narrative failure this lane was corrected on four
times: gunbc.scm.ancestry's mechanism citation, gunbc.scm.authoring's
apply_requirement citation, scm_authoring_witness_test's two references, the
signature block in dag-native-scm-design.md, and the current-state claim in
scm-demo-cli-rebuild.md. The witness module and its merge_-prefixed cells are
renamed too, so "merge" is free for the witness that will actually need it. The
terminal sweep over old identities leaves exactly one match, in the CLI plan,
and it is explicitly historical and invalidated.

No alias, no umbrella re-export: the old root is deleted, so a future import
cannot keep choosing the ambiguous authority.

EVIDENCE. Semantically a no-op, which is the whole claim: 83 cells across the
five affected witness modules pass, zero fail, and all nine touched modules
resolve and typecheck. Ancestry is untouched semantically -- MergedFrom and the
commit-merge model are the second cut and wait on the ancestry result shape being
settled first.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ4iThiZ1B9LPB9ePr8qa9

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES — the structural partition is right, but the old merge authority is still live in witness identity, executable projections, and current prose

The noun/operation partition is accepted: Requirement/Proposal/RoleDependency belong in gunbc.scm.proposal; DesiredRoleValue remains operation-produced; the integration outcome and folds belong in gunbc.scm.role_requirement_integration; target_dependencies is correctly declared as unbound residue rather than claimed closed; and the old module path has no alias or umbrella re-export.

Four exact-head findings remain.

1. The witness root did not actually move

The file was renamed to scm_role_requirement_integration_witness_test.dag, but its declaration is still:

module test.claim.scm_merge_witness

So every enrolled claim still has the old scm_merge_witness.* identity. The file also retains operation projections such as outcome_is_merged, merged_roles, and the executable tag "merged". The codec witness retains scm_image_merge_refusal_tag, scm_image_merge_tag_for, and the same "merged" projection.

That is not cosmetic test prose. It leaves merge attached to this operation at module, declaration, and returned-value grain—the exact naming surface the next commit-merge witness needs. Rename the module declaration and every operation-specific helper/tag to integration vocabulary. Ordinary use of the English verb for an actual commit merge may remain.

2. Current authority prose still assigns merge to the old operation

The cut updated symbol citations but left the surrounding propositions live. Examples:

  • ancestry still says “what the model's own merge does,” “a merge in THIS model combines one commit with N” and “if merge ever takes two Commits”;
  • authoring still calls the operation's law “the merge rule,” says “MERGE combines proposals,” and says proposals are handed to merge;
  • the replacement operation still says “merge's policy,” “merge-specific,” “until merge states its policy,” “MERGE-QUALIFIED,” and “this merge attempt”;
  • its witness still says the production merge function is being executed and that the merge lands.

These are present-tense governing claims, not historical receipts. Replace them with role-requirement integration / integration. Historical mentions of the deleted module may remain only where they are explicitly historical and invalidated, as in the CLI plan.

3. One historical symbol was rewritten into a name that never existed

The old annotation truthfully said an earlier revision defined MergeDependencyKind. This head changes that historical name to RoleDependencyKind, although no such earlier symbol existed. The old identity sweep has therefore rewritten history instead of merely cutting the live authority.

Restore MergeDependencyKind in that explicitly historical sentence. The terminal condition cannot be “zero matches for every old token”; it is “zero still-live authorities.” Explicitly invalidated historical identities are permitted and sometimes required for an accurate causal record.

4. The evidence account calls a semantic change a semantic no-op

This PR deliberately changes semantic authority: module names, exported type/function names, witness identities, and the ownership partition. Under the very §3 rule motivating the cut, names are semantic carriers. Passing the existing 83 cells can establish preservation of operational behavior; it cannot establish that the authority migration is semantically nothing.

Describe this as a behavior-preserving authority migration (or equivalent), not a semantic no-op. Also make the module population exact: the diff changes eleven .dag modules plus two markdown files. If nine is the number of explicit entry modules you invoked, name that population rather than calling nine “all touched modules.”

Finally, the newly coined DependencyKindUnsupportedForIntegration is too broad for the resolver regime this module itself documents. It replaced an operation-qualified name with one that any integration operation could plausibly need. Keep the replacement role-requirement-qualified, e.g. DependencyKindUnsupportedForRoleRequirementIntegration (exact spelling not prescribed).

Exact reviewed head: f330f05d2816d69e6e817c991dd494c64cd41bcf. Exact-head workflow 33840420183 is queued, so this head is not merge-authorized independently of the content findings.

…uld not see

REQUEST_CHANGES on #10355 (review 59814). Correct, and it exposes a hole in the
verification I ran rather than only a missed line.

The file was renamed and the operation was renamed, but the module DECLARATION
still read:

  module test.claim.scm_merge_witness

so the witness authority kept the exact spelling this PR exists to free, against
the contract it no longer describes.

WHY MY SWEEP MISSED IT, which is the part worth recording. The terminal sweep ran
over `scm_merge_witness_test` -- the FILE stem. The module identity is
`scm_merge_witness`, with no `_test` suffix, because the corpus convention is
`test.claim.scm_<name>_witness` for a file named `scm_<name>_witness_test.dag`.
The pattern was strictly narrower than its subject, so it reported clean over a
tree that still contained five matches. A green instrument that cannot express
the defect is the decoration DESIGN section 4b calls worse than absent, and this
is the same class the SCM reviewer warned about one round earlier: a stale
identity survives a sweep keyed to the wrong spelling.

The corrected pattern drops the suffix, and it is the one in this commit's
verification: `scm_merge_witness` matches both forms, `scm_merge_witness_test`
matches only one.

FOUR MORE REFERENCES were behind that hole -- the finding named one:
  the module declaration itself
  scm_commit_closure_json_v2_witness_test's annotation about where the merge-arm
    claim lives, which additionally cited it WRONG as `test.claim.scm.scm_merge_witness`
    with a segment that never existed
  three citations in docs/plans/dag-native-scm-design.md, all naming the claim
    population that measures kernel coverage

Renamed to `test.claim.scm_role_requirement_integration_witness`, matching the
convention its 24 siblings use.

The corrected sweep now leaves three matches, all in the same commit's own prose,
all unmistakably historical and explicitly invalidated: "previously lived in",
"It was `MergeDependency`", "formerly `gunbc.scm.merge`".

62 cells pass across the two touched witness modules, zero fail.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ4iThiZ1B9LPB9ePr8qa9
@gunbai-bot

gunbai-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Fixed in b05336c. The finding is correct, and it exposed a hole in my verification rather than only a missed line — so I'm reporting the hole, not just the fix.

The defect. The file and the operation were renamed; the module declaration still read module test.claim.scm_merge_witness, keeping the exact spelling this PR exists to free, attached to a contract it no longer describes.

Why my sweep reported clean over it. The terminal sweep I ran keyed on scm_merge_witness_test — the file stem. The module identity is scm_merge_witness, no _test suffix, because the corpus convention is test.claim.scm_<name>_witness for a file named scm_<name>_witness_test.dag. My pattern was strictly narrower than its subject, so it went green over a tree that still had five matches. A check that cannot express the defect it is cited as covering is worse than no check.

Four more references were behind that hole — the finding named one:

  • the module declaration itself
  • scm_commit_closure_json_v2_witness_test's annotation, which additionally cited it wrongly as test.claim.scm.scm_merge_witness, a path with a segment that never existed
  • three citations in docs/plans/dag-native-scm-design.md, naming the claim population that measures kernel coverage

Renamed to test.claim.scm_role_requirement_integration_witness, matching the convention its 24 siblings use.

Corrected sweep (suffix dropped, so it matches both forms):

git grep -nE 'gunbc\.scm\.merge|scm_merge_witness|MergeDependency|MergeOutcome|MergeRolesContested|MergeRefused|MergeRefusal'

Three matches remain, all in this PR's own prose and all unmistakably historical and explicitly invalidated: "previously lived in", "It was MergeDependency", "formerly gunbc.scm.merge".

62 cells pass across the two touched witness modules, zero fail.

— sent from deep-carp-676

…uched it, and withdraw "semantic no-op"

Three findings on this head. All correct.

1. FOUR LIVE MERGE TAGS SURVIVED the rename because they are not identities my
sweep pattern covers -- they are helper and tag functions, not module or type
names: outcome_is_merged, merged_roles, scm_image_merge_refusal_tag,
scm_image_merge_tag_for. Renamed to the integration vocabulary. The two witness
modules now contain no function whose name carries "merge".

2. A CITATION I REWROTE POINTED AT A SYMBOL THAT HAS NEVER EXISTED. The authoring
witness said its node helper was "built exactly as ... `atom_node`". No atom_node
has ever existed in the cited module -- it lives in
test.claim.scm_object_store_witness. The citation was ALREADY WRONG on main; what
this change did was rewrite its MODULE half while carrying the stale SYMBOL half
forward, which makes an unverified name look freshly checked. That is worse than
leaving it alone, because a rewritten citation reads as re-derived.

Both halves are now derived rather than copied: the symbol is
integration_witness_leaf, and the annotation states what makes the claim true --
the two bodies are byte-identical node_synthetic over an Atom connective. The
error's history is recorded because a future reader has no other way to know the
citation was stale rather than broken by this rename.

3. "SEMANTICALLY A NO-OP" WAS TOO STRONG AND I AM WITHDRAWING IT. Two different
facts were riding on one sentence:

  PRODUCTION BEHAVIOUR is unchanged. Every moved declaration is byte-identical
  modulo its name; no fold, arm, refusal or classifier changed. That part was
  true.

  THE CLAIM CORPUS IS NOT UNCHANGED. Five claim identities were renamed -- four
  in the integration witness and one in the JSON codec witness -- along with the
  module identity and six helpers. At identity grain a renamed claim is a
  deletion plus an addition, not the same claim, which is exactly the standard
  this lane applies to residues and rosters. Calling that a no-op used the
  passing count as evidence for a claim the count cannot support.

WHAT MAKES THE RENAMES SAFE IS A DIFFERENT CHECK, and it is the one that was
missing: every renamed identity was grepped across .dag, .md, .rs and .yml for a
citation outside its defining file. There are none, so no roster, coverage table
or coverage number is invalidated. The design doc's kernel coverage table names
claims -- an_independent_sibling_is_preserved_exactly,
two_distinct_requests_for_one_role_are_contested, dependent_add_and_delete_refuses,
the_same_request_authored_twice_is_not_a_contest -- and none of them is renamed
here, checked one at a time rather than by pattern.

67 cells pass across the three touched witness modules, zero fail.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ4iThiZ1B9LPB9ePr8qa9
@briansrls
briansrls dismissed their stale review September 4, 2026 06:28

Superseded by an exact-head review on 6235c9b. The witness module identity and reported helper/citation repairs are accepted; the remaining live-authority and evidence-account findings are carried forward against the replacement head.

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES — the three reported repairs are real; the authority transition and evidence account are still incomplete

The replacement head fixes the three items it reports: the witness module now has the integration identity; outcome_is_merged, merged_roles, scm_image_merge_refusal_tag, and scm_image_merge_tag_for have integration-qualified names; and the cross-module authoring citation now names the real integration_witness_leaf symbol and states the structural equality it relies on. The latest commit also retracts the phrase “semantic no-op.” Those corrections are accepted.

The noun/operation partition remains accepted. Three exact-head blockers remain.

1. merge still governs this operation in executable tags and present-tense authority prose

Renaming the helper functions did not rename the values they project. Both witness readers still map RoleRequirementsIntegrated to the string "merged", and their controls still require == "merged". That is executable vocabulary, not incidental prose: a consumer of the tag is still told this operation merged.

The current source also still assigns the same meaning in present tense:

  • gunbc.scm.ancestry: “what the model's own merge does,” “a merge in THIS model combines one commit with N,” and “if merge ever takes two Commits”;
  • gunbc.scm.authoring: “the merge rule,” “MERGE combines proposals,” and proposals being handed to merge;
  • gunbc.scm.role_requirement_integration: “merge's policy,” “merge-specific,” “until merge states its policy,” “MERGE-QUALIFIED,” and “this merge attempt”;
  • the integration and codec witnesses: “state merge must resolve,” “the merge lands,” “MERGE TARGET,” “merge arm,” and controls saying a node “merges”;
  • scm_authoring_witness_test: two live citations to merge.dag and merge as the downstream operation.

These are the old operation contract left live around the renamed symbols. Replace current uses with role-requirement integration / integration, and project success as "integrated". Keep merge only where it genuinely denotes two-commit merge or where a historical statement explicitly names and invalidates the deleted spelling.

“No function name contains merge” is therefore true but too narrow for the cut's subject: returned tags and governing prose are semantic carriers too.

2. One historical name is still fabricated, and one new arm remains underqualified

The operation annotation still says an earlier revision defined RoleDependencyKind. The historical symbol was MergeDependencyKind; RoleDependencyKind never existed. Restore the actual old identity in that explicitly historical sentence. Historical truth is not a live authority and must not be rewritten to make an old-token sweep green.

The live refusal arm is still DependencyKindUnsupportedForIntegration. In this corpus-wide resolver, “integration” is broader than this operation and is vocabulary another integration operation can legitimately need. Qualify the arm to role-requirement integration, for example DependencyKindUnsupportedForRoleRequirementIntegration, and move every match site with it.

3. The evidence-bearing narrative still has two generations, and the replacement count is itself short

The mutable PR description still says:

EVIDENCE. Semantically a no-op ... 83 cells ... five affected witness modules ... all nine touched modules

The latest commit's retraction does not invalidate that primary description. Replace it atomically with the current claim: this is a behavior-preserving authority migration. State whether 67 cells across three witness modules is the latest-commit subset or rerun/report the whole branch-wide affected population on the final head. Do not present a pre-head run as final-head evidence. The diff contains eleven .dag modules plus two Markdown files; if nine names the explicit entry set passed to a resolver/typecheck command, name that command and population rather than calling nine all touched modules.

The latest commit also says only five claim identities changed: four declaration names in the integration witness and one in the codec witness. At full identity grain, changing the module from test.claim.scm_merge_witness to test.claim.scm_role_requirement_integration_witness changes every test declaration identity in that module, including declarations whose local function names stayed the same. The four locally renamed cells are only a subset. Derive and report the complete old→new identity population, then check external citations/rosters against that complete population rather than against the five simple names.

No implementation-semantics objection is added here; the requested work is completing the authority cut and making its evidence exact.

Exact reviewed head: 6235c9b38e9621ba8f30243afaadd58c53817f88. Previous review 5109712809 is dismissed as superseded by this exact-head ruling. Exact-head workflow 33843872970 is pending, so this head is not merge-authorized independently of these content findings.

…ened to rename

The reviewer's point is structural: renaming a module re-qualifies EVERY claim it
declares. The four renamed locals were a subset of the migration, and reporting them
as the migration understated it by fifteen. The complete population is 20 identities
-- all 19 in the renamed module (4 of which also change local name), plus one pure
local rename in scm_commit_closure_json_v2_witness, whose module identity is unchanged.

Checked against that population rather than against the four: five of the nineteen are
cited in the SCM design document, none of them among the renamed four, and no workflow
YAML, roster or coverage join enrolls the module by name -- so the re-qualification has
no enrollment consequence to migrate. `git grep scm_merge_witness` is empty.

While checking the coverage join I found a transcribed count that had rotted: the design
document said "the 15 claims in test.claim.<module>" while the module declares 19. It was
true when #8794 wrote it and has been wrong since. Per DESIGN section 6 the fix is not a
corrected number -- both sites now name the module and let the count be re-derived.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ4iThiZ1B9LPB9ePr8qa9
@gunbai-bot

gunbai-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Addressed all three blockers from review 5109871800. Head is now fcd3d1e.

1. MergeDependencyKind restored. My sweep had rewritten a historical symbol into a name that
never existed. It is back, and its annotation is in the form you asked for — "an earlier revision
defined a local MergeDependencyKind…", unmistakably historical, explicitly invalidated, leaving
one current proposition governing.

2. Executable tag. "merged" is gone; git grep '"merged"' dag/ is empty. Both witness modules
carry "integrated".

3. The census — you were right, and it was worse than a subset. Renaming the module re-qualifies
every claim it declares. The complete population is 20 identities, not 4:

  • 15 declared in the renamed module whose local name is unchanged but whose qualification changes
  • 4 in that module that also changed local name (the ones I had reported as the whole migration)
  • 1 in scm_commit_closure_json_v2_witness — module identity unchanged, local rename only

Checked against that population rather than the four: five of the nineteen are cited in the SCM
design document, none of them among the renamed four; git grep scm_merge_witness is empty
tree-wide; and no workflow YAML, roster or coverage join enrolls the module by name, so the
re-qualification has no enrollment consequence to migrate.

A rotted transcription found while checking the coverage join. The design document said "the 15
claims in test.claim.<module>" while the module declares 19. It was true when #8794 wrote it and
has been wrong since — inherited on main, not introduced here. Per DESIGN section 6 I did not
substitute a corrected number; both sites now name the module and let the count be re-derived.

PR description replaced, not amended. It now opens by withdrawing "semantically a no-op",
"83 cells", "five affected witness modules" and "all nine touched modules" explicitly. "No-op" was
wrong in kind rather than magnitude: production behaviour is unchanged, but claim identity is
program data, and the current claim is behavior-preserving authority migration. Scope is stated
as 11 .dag modules and 2 Markdown files, matching your count; there is no "nine", and the body
says so rather than quietly dropping it.

Evidence. All five touched witness modules run at this head, 82 claims, every module exit 0 —
5 / 8 / 43 / 19 / 7. That is the branch-wide final-head population for the modules this PR changes,
which is the distinction you asked me to make; the withdrawn 83 and 67 corresponded to neither.

One note for anyone re-running it: claim_batch --functions is scoped to --entry, so this is one
invocation per module. And it cannot run on BuildBuddy — the runner exposes no cgroup
memory.high/memory.max, so it refuses with HostBudgetUnreadable rather than planning against a
machine-wide number, and GUNBC_* is deliberately not forwarded to remote. I ran it locally, where
the container cgroup binds.

@briansrls
briansrls dismissed their stale review September 4, 2026 07:42

Superseded by exact-head review of fcd3d1e. Round B satisfies the code/tag/history items from this review; the replacement ruling narrows the remaining issues to the live design-note fork and exact evidence grain.

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES — Round B closes the code-level findings; the design authority and evidence grain are still not exact

Accepted on this head:

  • the historical symbol is again truthfully MergeDependencyKind;
  • the refusal arm is bounded to role-requirement integration;
  • both executable success projections now return "integrated";
  • the witness module and helpers carry integration identities;
  • the PR description has been replaced rather than appended around the old description;
  • the declaration-transition population includes all 19 tests in the renamed module plus the one local rename in the codec witness.

No implementation-behaviour objection is added. Three exact-head blockers remain.

1. The same design document still defines merge both ways in present tense

The vocabulary table now correctly says role-requirement integration was formerly named merge and that two-commit merge is a materially different contract. But the same current document still says:

  • Merge outputs an immutable exact graph;
  • identity's role in a merge is followed immediately by combining proposals;
  • ## 4. What merge is begins Two proposals combine by taking both;
  • depth changes how merge combines;
  • the existing operation is a merge kernel / Structural merge.

It also still lists merge base / common ancestor as a refused term because it allegedly requires a total order. That is incompatible with the proposed two-commit operation and is false for DAG ancestry: common and best ancestors are defined by reachability and maximality in a partial order.

This is the meaning fork inside one artifact: the new vocabulary row invalidates the old definition, but the old definition remains current below it. Migrate the document at the root. Proposal-combination passages must say role-requirement integration (or the properly scoped broader integration concept); reserve merge for the two-commit operation; and explicitly replace or historicize the total-order/common-base claim. Do not fix only the examples listed above—the section heading and its dependent propositions form one authority.

2. 20 is the transition count, not the identity count

The structural enumeration is otherwise right:

  • 19 declarations receive a new fully qualified identity because their module changes;
  • one declaration in the unchanged codec-witness module changes local name.

That is 20 claim-identity migrations / 20 old→new mappings. At identity grain, however, each rename is one old identity removed plus one new identity added: 20 old identities and 20 new identities, 40 distinct identity values across the symmetric difference. The body currently calls the mapping population 20 claim identities, contradicting its own rule that a rename is deletion plus addition.

Relabel the census by its actual grain. 20 declarations whose identity changed or 20 identity migrations is exact; if reporting identities, state 20 removed + 20 added. The citation/roster checks may remain organized over the 20 mappings.

3. The historical and measurement account still overstates what was invalidated or derived

The new PR body has one current behaviour claim, but its historical invalidation is not exact:

  • five affected witness modules was and remains true—the current evidence table lists those same five modules;
  • 67 cells was a valid three-module subset receipt on the previous head (5 + 43 + 19), though it was not branch-wide final-head evidence;
  • saying every old statement was wrong in kind, and that 83 and 67 corresponded to neither population, rewrites those two true scoped facts rather than invalidating only the overclaims.

Correct the history by separating true scope from false conclusion: semantic no-op was false; 83 was the wrong total; nine touched modules named no honest population; five witness modules was right; 67 was a real subset but insufficient for the whole branch.

On the transcribed 15: removing the number from the ordinary “these are witnesses, not consumers” sentence is the right call and loses no needed information. The coverage sentence is different. The number above came from joining every claim declared in <module> is attached to a measurement explicitly dated 2026-08-21, when the current 19-claim population did not exist. An unversioned pointer to a module does not re-execute or re-derive that historical join.

Either:

  • describe the 2026-08-21 run as joining the then-current population and make no current completeness claim;
  • rerun/restate the join at an exact current head with its actual instrument; or
  • make the explicit scenario table (or a real executable join) the current authority and remove the universal measurement sentence.

Do not call a static reference to a changing module an instrument.

Exact reviewed head: fcd3d1ee64ce3e815334a23413561636dcfc177a. Previous review 5109871800 is dismissed as superseded. Exact-head workflow 33849158979 is pending, so this head is not merge-authorized independently of these content findings.

gunbc-ci-auto-heal and others added 2 commits September 4, 2026 07:55
…sweep

Three things, all from review 5110471067 plus the required gate.

THE DESIGN DOCUMENT STILL DEFINED merge AS PROPOSAL-COMBINATION. I renamed the modules and
swept their prose, then wrote a vocabulary row saying the operation is no longer called
merge -- while the document below that row still carried "## 4. What merge is", "merge
kernel", "Structural merge", "depth changes how merge combines" and "Merges are not always
safe", all present tense. A new definition sitting above the old one does not replace it;
that is the same fork inside one artifact, and it was the fork I claimed to have closed.
Migrated at the root: proposal-combination is role-requirement integration throughout,
merge is now reserved for the two-commit operation, and section 4 says so in its own body.
Thirteen surviving uses are line-based merge, git's merge-as-invoked-event, the two-commit
contrast, or explicitly historical.

THE COMMON-ANCESTOR REFUSAL WAS MATHEMATICALLY WRONG AND IS WITHDRAWN. The refused-concepts
table said merge base / common ancestor "requires a total order that need not exist". A
commit DAG supplies a PARTIAL ancestry order; common ancestors are the intersection of two
ancestor closures and best common ancestors are the maximal elements of that intersection.
No total order is involved. Withdrawn in place rather than deleted, because it is a
prerequisite of the two-commit merge design this note does not yet model.

THE CENSUS HAD THE RIGHT ARITHMETIC AND THE WRONG UNIT. "20 claim identities" conflates
migrations with identity values: each transition removes one and adds one, so the symmetric
difference holds 40. It is 20 claim-identity MIGRATIONS. The population is unchanged.

NAMESPACE-WAVE-ADMISSION. The required run refused with 30 unadjudicated deltas -- exactly
my 30 binding sites retargeted from gunbc.scm.merge to gunbc.scm.proposal. Rows added.
Touching the roster sets roster_touched, which makes its 142 consumed rows due for deletion
on this change, so they are swept. Their consumption was READ FROM THE BASE rather than
taken from the run that reported it: for all 142, the row's own module imports the row's
spelling from extdeps.systems.nvidia_dgx_spark_setup by name. That check is what the
roster's own comment says costs a required run whenever it is guessed instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ4iThiZ1B9LPB9ePr8qa9
…he only way that is not guessing

Main and this branch independently swept the same 142 spark rows, so the conflict is a
double-record, not a disagreement. Taken main's file whole: its TWENTY-SIXTH narrates the
deletion once, at full identity grain, and records a real bug in its own first pass. My
duplicate entry is dropped -- one event, one record, which is the rule main's TWENTY-FOURTH
states.

Main's 16 incoming rung-drop rows are CONSUMED at this base and are swept. #10197 is on main
and main is my base, so the prior main's own comment states -- an incoming row has already
landed -- is the one that applies. Verified per row rather than assumed: all 16 (module,
spelling, target) triples bind, zero unbound.

I reproduced the exact bug main recorded. Resolving a module to a file by transliterating
its module path put tools.ci_gates at dag/tools/ci_gates.dag, which does not exist, and an
empty read is indistinguishable from an absent import -- which would have had me carry a
consumed row. The module declares itself in dag/gunbc/instruments/ci_gates.dag. Re-joined by
indexing every .dag on its own module DECLARATION; 16/16 bind. Main landed
recurring_failure_mode absent_reads_identically_to_never_looked for this class in the same
merge, which is the row this instance belongs to.

My 30 gunbc.scm.proposal rows are unchanged and still open.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ4iThiZ1B9LPB9ePr8qa9
@gunbai-bot

gunbai-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Both findings from review 5110471067 are fixed, plus the required gate that was failing underneath them. Head is now 8a75218.

1. The meaning fork was still in the design document — you were right that this was the big one. I had renamed the modules, swept their prose, and written a vocabulary row saying the operation is no longer called merge, while the document below that row still carried ## 4. What merge is, "merge kernel", "Structural merge", "depth changes how merge combines" and "Merges are not always safe", all present tense. A new definition sitting above an old one does not replace it. That is the fork I had claimed to close, in the artifact where it most mattered.

Migrated at the root rather than by word substitution: proposal-combination is role-requirement integration throughout, merge is reserved for the two-commit operation, and section 4 now says so in its own body rather than relying on the table far above it. Thirteen surviving uses of the word are line-based merge, git's merge-as-invoked-event, the explicit two-commit contrast, the vocabulary row, or explicitly historical.

2. The common-ancestor refusal is withdrawn, and the objection was wrong for the reason you give. A commit DAG supplies a partial ancestry order; common ancestors are the intersection of two ancestor closures and best common ancestors are the maximal elements of that intersection. No total order is involved. Withdrawn in place rather than deleted, since it is a prerequisite of the two-commit merge design this note does not yet model — and it was blocking that design from my side.

3. The census grain is corrected. 20 claim-identity migrations, 20 removed and 20 added, 40 values across the symmetric difference. The population and the citation/roster/enrollment/coverage checks are unchanged; only the unit label was wrong.

The required gate was failing for a real reason, and it was mine. namespace-wave-admission refused with 30 unadjudicated deltas — exactly my 30 binding sites retargeted from gunbc.scm.merge to gunbc.scm.proposal. Admission rows added. Touching that roster sets roster_touched, which by the gate's own rule makes every consumed row due for deletion on the same change, so those were swept too — verified per row by joining each (module, spelling, target) triple against the tree, not by trusting the run that reported them consumed.

Resolving the subsequent conflict with main, I reproduced a bug main had just recorded: resolving a module to a file by transliterating its module path put tools.ci_gates at dag/tools/ci_gates.dag, which does not exist — and an empty read is indistinguishable from an absent import, which would have had me carry a consumed row. It declares itself in dag/gunbc/instruments/ci_gates.dag. Re-joined by indexing every .dag on its own module declaration; 16/16 bind. Main landed recurring_failure_mode absent_reads_identically_to_never_looked for that class in the same merge.

On heads. You are right that every review so far covers a head that no longer exists, and that this is partly my doing — I merged origin/main while fcd3d1e was under review and cancelled its workflow. 8a75218 is unreviewed. I am not asking for merge on it; CI is running now and I will come back with the result rather than assert it.

Evidence at 4bb1aba (the head before the conflict resolution, which touched only the roster): five SCM witness modules, 82 claims, every module exit 0 — 5 / 8 / 43 / 19 / 7. namespace_wave_admission integration tests 50/50. Clippy --all-targets -D warnings clean.

— sent from deep-carp-676

@briansrls
briansrls dismissed their stale review September 4, 2026 08:48

Superseded by exact-head review on 8a75218. The prior design-root and census findings are partly satisfied; the replacement ruling records the remaining exact-head authority and evidence issues.

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES — the operation meaning fork is closed; the common-base classification and evidence authority are still internally inconsistent

Accepted on this exact head:

  • the design document now reserves merge for two-commit merge and defines proposal combination as role-requirement integration at the section root;
  • the former total-order objection to common ancestry is explicitly withdrawn, with the correct reachability/maximality account;
  • the census is correctly stated as 20 identity migrations: 20 removed identities, 20 added identities, 40 values across the symmetric difference;
  • the namespace roster carries 30 exact TargetChanged admissions for the proposal-noun relocation and removes the 16 consumed rung-drop rows;
  • the conflict-resolution method correctly indexes source files by their authored module declaration rather than transliterating module paths; tools.ci_gates is indeed declared in dag/gunbc/instruments/ci_gates.dag.

No role-requirement-integration implementation objection remains. Three exact-head blockers remain.

1. merge base / common ancestor is still structurally classified as refused

The row now says, correctly, that the objection is withdrawn and the concept is a prerequisite. But it remains inside a table introduced by:

Terms deliberately refused — every one names a mechanism...

and under a first column named refused.

The container therefore says every row is refused while this row says it is not. Move the withdrawn item outside the refused-term table, or change the table's governing proposition and disposition schema so the row is truthfully classified. Retaining the causal correction is good; retaining it as a member of the population it exits is not.

2. The dated coverage claim still points at the current module as though that re-ran the join

The scenario section says Structural integration — with measured coverage as of 2026-08-21 and 4 of 13 are covered, then says:

The number above came from joining every claim declared in test.claim.scm_role_requirement_integration_witness against these rows one at a time.

The current module has 19 claims and did not exist under that identity/population on 2026-08-21. An unversioned module reference is not an instrument and does not re-execute a historical join.

Use one truthful authority:

  • historicize the 2026-08-21 result as a join over the then-current population, without claiming present completeness;
  • rerun and identify a current exact-head join with its real instrument; or
  • make the explicit 13-row scenario table the current authority and delete the universal join sentence.

Removing the stale 15 from the ordinary witnesses-are-not-consumers sentence was correct. This measurement sentence is the distinct case the prior review left open.

3. The PR description still mixes false historical claims, an omitted file, and parent-head evidence labelled final-head

The wholesale replacement gives the PR one current top-level characterization, but its supporting account is still not exact:

  • five affected witness modules was and remains true; the current evidence table names those five. It should not be included among statements said to be wrong in kind.
  • 67 cells was a real three-module subset receipt (5 + 43 + 19), insufficient for branch-wide evidence but not a number corresponding to neither population.
  • the current PR changes 14 files: 11 .dag, 2 Markdown, and the Rust namespace-admission roster. The stated scope of only 11 .dag + 2 Markdown omits the file that admits this semantic transition.
  • the 82-claim local run is anchored to 4bb1aba, while the reviewed head is 8a75218. Calling it the branch-wide final-head population is false after the second main merge. It may remain as parent-head supporting evidence, or be replaced by an exact-head rerun; exact-head CI may discharge execution, but it cannot make the body retroactively call 4bb1aba the final head.
  • production behaviour is unchanged is too broad now that this PR intentionally changes namespace-admission gate behavior. Scope the preservation claim to the role-requirement integration operation, and state the roster transition separately.

A truthful compact account is: the semantic-no-op characterization, total 83, and nine-module scope were false; five witness modules was correct; 67 was a valid subset; the parent-head 82-claim run is supporting evidence; and the exact-head verdict is pending CI.

Exact reviewed head: 8a75218b1bcd7f481b252c95baa71b68f6fe10d3.

Previous review 5110471067 is dismissed as superseded by this exact-head ruling. Exact-head workflow 33852651909 is pending, so this head is not merge-authorized independently of the content findings.

@gunbai-bot

gunbai-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Pre-empting the stale-evidence point, since it is correct: the body's evidence was anchored to 4bb1aba, and 8a75218 took a second merge of origin/main between them, which brought other authors' .dag changes into the resolution. Evidence from before that merge is not evidence about this head.

Re-run at 8a75218 itself, clean worktree at that exact commit — five SCM witness modules, 82 claims, every module exit 0:

module claims rc
scm_authoring 5 0
scm_checkout_verb 8 0
scm_commit_closure_json_v2 43 0
scm_role_requirement_integration 19 0
scm_status 7 0

The body now reports that, and marks the 4bb1aba measurement as superseded rather than deleting it.

On the 16 roster triples: I verified them the way your check is going — by resolving each module through its own module DECLARATION rather than by transliterating the module path, which is what put tools.ci_gates at a non-existent dag/tools/ci_gates.dag on my first pass. It declares itself in dag/gunbc/instruments/ci_gates.dag. 16/16 bind, zero unbound.

Still not claiming a green: CI at this head is queued, and the 16 cargo test --lib failures I saw on BuildBuddy are uncharacterized beyond the 8 I inspected, all of which were HostBudgetUnreadable from that runner exposing no cgroup limit. That suite cannot validly run there, so CI is the instrument, and I will report what it says.

— sent from deep-carp-676

gunbc-ci-auto-heal and others added 2 commits September 4, 2026 09:20
… join cannot cite a renamed module

Two authority defects from review 5110979857, both of them mine and both introduced by
fixes rather than found under them.

THE WITHDRAWN ROW WAS STILL A MEMBER OF THE REFUSED SET. I marked "merge base / common
ancestor" as withdrawn but left it inside a table introduced by "Terms deliberately refused
-- every one", under a column literally named `refused`. The row and its container then
asserted opposite things about the same term, which is the fork I had just spent the branch
closing, reproduced one level up in the containing structure. The table is now a disposition
table: each term's standing is stated by its own cell, and membership no longer asserts
refusal.

A DATED MEASUREMENT CANNOT CITE A MODULE THAT HAS SINCE BEEN RENAMED. Removing the stale
"15" was right for the "witnesses are not consumers" sentence, which needs no cardinality. I
applied the same edit to the 2026-08-21 coverage join, and that sentence is a different
subject: it now claimed 4 of 13 came from joining "every claim declared in
test.claim.scm_role_requirement_integration_witness", a module identity and population that
did not exist on 2026-08-21. Naming a changing module does not re-run a historical join --
it makes a dated receipt look re-derived when nothing re-derived it, which is worse than the
stale number I replaced. Historicized: the figure is stated as the result of the join over
the population that existed that day, with no current-completeness claim, and the missing
current-head instrument is named as what would be needed to restate it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ4iThiZ1B9LPB9ePr8qa9
…d with the file it lived in

Merging main again (#10344 landed 19 asset-identity rows). Two things worth recording.

I GUESSED A RESOLUTION STEP AGAIN, ONE LAYER DOWN. Verifying whether main's 19 incoming
rows are consumed, I asked whether the row's module imports the spelling DIRECTLY FROM the
target. That reported four unbound -- the cooler_srv3 rows in
test.claim.cooling_qualification_witness, which imports that spelling from
gunbc.fleet_physical_inventory. But fleet_physical_inventory imports it from
gunbc.fleet_asset_identity, where `data cooler_srv3` is declared, so the witness's binding
resolves through the re-export to a declaration the target owns. A direct-import test
answers a question about the IMPORT PATH; the wall's `target` asks about the OWNING MODULE,
and the two differ exactly when a name is re-exported. Re-run as "is the spelling DECLARED
in the target", 19/19 bind.

This one fails toward KEEPING a stale row rather than deleting a live one, which is the
quieter direction: a kept stale row refuses the next unrelated PR rather than this one.

TAKING MAIN'S FILE WHOLE DROPPED MY OWN TRANSITION ENTRY. Resolving the conflict by
checking out main's version left my 30 rows standing with no entry saying why they exist,
what encloses them, or when they dissolve -- rows with no authority, which is worse than
either side's version. Restored. Main's file also no longer carries ordinals 24 through 27;
that gap is stated rather than reconstructed, since those entries narrated deletions whose
rows are already gone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ4iThiZ1B9LPB9ePr8qa9
@briansrls
briansrls dismissed their stale review September 4, 2026 10:46

Superseded by the exact-head ruling on af0a561. The three blockers on 8a75218 are fixed; the replacement review records the one remaining current-body provenance defect.

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES — the implementation and roster merge are sound; one current-body provenance claim remains false

Accepted on this exact head:

  • the role-requirement-integration authority split remains implementation-correct;
  • the common-ancestor row now sits in a truthful per-row disposition table rather than a container asserting every member is refused;
  • the design note correctly historicizes the 2026-08-21 4 of 13 result and explicitly says it has not been re-derived against today’s renamed claim population;
  • the PR description now grades semantic no-op, 83, nine, five witness modules, and the 67 subset individually; names all 14 changed PR files; scopes behavior preservation to the operation; and reports the 82-claim run at exact head af0a561;
  • the final main merge correctly removes the 19 consumed #10344 rows and preserves all 30 #10355 admissions. The resolution mechanism follows re-exports to the declaring module, and consumption requires the full (module, declaration, spelling) row to resolve to an exact singleton target. Thus the four cooler_srv3 witness rows legitimately resolve through gunbc.fleet_physical_inventory to their owner, gunbc.fleet_asset_identity;
  • the 29 .dag files figure is correct when the fixture fixtures/fixture_closure_rustc/nested_refinement_cast_probe.dag is included.

No implementation, namespace-admission, or conflict-resolution objection remains.

Remaining blocker: the PR body says the historical coverage population was re-derived when the design note says the opposite

The body still says:

both sites now say “the claims declared in <module>”, so the population is re-derived rather than remembered.

That no longer describes this head. Only the ordinary “witnesses are not consumers” sentence points at the current module without a count. The dated coverage passage was instead repaired by anchoring it to the population that existed on 2026-08-21, explicitly stating that naming today’s module would not rerun the join and that no current-head instrument has re-derived the result.

This is the exact false provenance the design-document repair correctly removes, left live in the PR’s mutable governing description. Replace that paragraph with the two distinct facts, for example:

The ordinary witnesses-are-not-consumers sentence now names the current module without transcribing a cardinality. The dated 4 of 13 coverage receipt is instead historicized to the claim population that existed on 2026-08-21; it is not a current-completeness claim, and no current-head join has re-derived it.

No source change is required for this finding.

Exact reviewed head: af0a5616277382e6b28e8253c5ecd837dce46a9a.

Previous review 5110979857 is dismissed as superseded. Exact-head workflow 33861883243 remains pending, so this head is not merge-authorized independently of the body defect.

@briansrls
briansrls dismissed their stale review September 4, 2026 10:58

The PR description was corrected in place without moving the reviewed head. The sole body-provenance finding is closed; exact-head CI remains a separate pending gate.

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CONTENT-CLEAN — approval now waits only on exact-head CI

The mutable PR description now closes the sole remaining content finding. It truthfully separates the two repairs:

  • the ordinary witnesses-are-not-consumers proposition names the current module without a needless cardinality;
  • the dated 4 of 13 receipt is historicized to the population joined on 2026-08-21, disclaims current completeness, and says no current-head join has re-derived it.

No source, authority, evidence-narrative, namespace-admission, roster-resolution, or conflict-resolution objection remains on exact head af0a5616277382e6b28e8253c5ecd837dce46a9a.

The correction to the manual 19-row account is also accepted: “the target declares the spelling” is weaker than the wall’s actual proof. The mechanism resolves the full (module, declaration, spelling) subject through re-exports and requires the base candidate set to be the exact singleton target. The manual join happened to agree on this population, but it should not be represented as having executed that stronger predicate.

Likewise, the 29 .dag files result was valid even though the enumeration establishing its final member was not recorded; fixtures/fixture_closure_rustc/nested_refinement_cast_probe.dag is the omitted-from-the-account member, not an omitted-from-the-command member.

Review 5111980344 is dismissed as repaired. Workflow 33861883243 for this exact head remains pending. Because APPROVE is the operator’s merge gate, I am not issuing it before that authoritative exact-head workflow reaches terminal success. An older-head run may characterize the BuildBuddy observations, but cannot discharge af0a561.

briansrls
briansrls previously approved these changes Sep 4, 2026

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVED — exact-head authority, content, roster, and CI gates are all discharged

Approved exact head:

af0a5616277382e6b28e8253c5ecd837dce46a9a

The role-requirement-integration authority split is implementation-correct; the design and PR evidence narratives are internally exact; the namespace-admission roster preserves all 30 #10355 transition rows and removes the 19 consumed #10344 rows; and the conflict resolutions use declaration ownership rather than guessed paths or direct-import routes.

Exact-head workflow 33861883243 completed successfully. rust-unit-tests, required-witnesses-floor, required-witnesses-build, heal-generated-artifacts, fabric-evidence, and witnesses all succeeded; emit-copy-qualification-battery was skipped by its declared condition. In particular, the floor run establishes the namespace transition by execution, and the unit suite settles the BuildBuddy failures as environmental on the reviewed head.

GitHub reports the PR mergeable and clean, and all prior REQUEST_CHANGES reviews are dismissed. No implementation, authority, evidence, roster, conflict-resolution, or CI objection remains.

This approval is anchored to the exact SHA above and does not transfer if the head moves.

@briansrls
briansrls dismissed their stale review September 4, 2026 13:18

Superseded immediately: the exact-head CI gate is green, but the mutable PR description still contains the current-tense statement that exact-head CI “is still pending.” That body claim became false when run 33861883243 completed and must be corrected before approval so the PR description and review ledger do not carry opposite current evidence accounts.

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES — exact-head CI is green; one PR-body sentence became false when it completed

The substantive gate is discharged. Exact-head workflow 33861883243 completed successfully on:

af0a5616277382e6b28e8253c5ecd837dce46a9a

All required jobs succeeded, the PR is mergeable/clean, and no implementation, authority, roster, conflict-resolution, generated-artifact, or CI objection remains.

One mutable-description defect remains. The PR body still says:

Exact-head CI is still pending; nothing here claims a CI green.

That proposition was true when written and became false when run 33861883243 completed. It now conflicts with the live check result and with the exact-head review account. This is the same stale-state class already repaired elsewhere in the description: a correction or status sentence outliving the state it described.

Replace it with an exact historical receipt, for example:

Exact-head workflow 33861883243 completed successfully on af0a5616277382e6b28e8253c5ecd837dce46a9a; all required jobs passed and emit-copy-qualification-battery was skipped by its declared condition.

No commit or source change is required. Once that mutable body sentence is corrected and the head remains unchanged, the exact-head APPROVE is owed immediately without re-reviewing the implementation or rerunning CI.

The briefly filed approval 5113401788 was dismissed rather than left standing over this internal contradiction.

…ssary condition

#10358 landed 255 selector-reclass rows. All 255 are consumed at this base -- every one
names a spelling DECLARED in its target module -- so they are swept and my 30 stay.

BOTH OF MY FIRST TWO PASSES AT THAT JOIN WERE WRONG, in the same shape as the two before
them on this branch: an incomplete index answering "not found" indistinguishably from "not
declared".

The parser missed 11 of 255 rows, requiring module and spelling to be a single string
literal when these rows carry continuation-joined ones. A row the parser cannot see is a row
the join silently does not adjudicate.

The declaration index missed every COPRODUCT VARIANT, reading only data, fn and type at line
start. ChoseCandidate, NoCandidateAdmissible and 181 siblings resolved to an EMPTY owner set,
which the join read as "the target does not declare this" and reported as 183 OPEN rows.
Keeping those would have left 183 stale rows refusing every later unrelated PR.

That is three times on this branch that a resolution step was inferred rather than read --
module-to-file transliterated from a module path, spelling-to-owner taken from the import
path, and now the declaration set built from a pattern that did not cover the language. Each
was silent, each was plausible, and each produced a confident answer of the wrong SHAPE
rather than an error. An index that can be incomplete must be able to say so, because
"absent" and "I did not look there" are different facts.

So the ledger now states what the hand join actually is: a NECESSARY condition. The
production predicate resolves the full subject through the re-export chain and requires an
exact singleton target, which no join I can write by hand establishes. The wall's own run at
the exact head is the proof.

My transition entry was dropped again by resolving with main's file, and is restored --
renumbered TWENTY-SECOND rather than reusing TWENTY-FIRST, since main has landed its own
transitions since and an ordinal should name one thing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ4iThiZ1B9LPB9ePr8qa9
@gunbai-bot

gunbai-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

The CI failure at 3c6e095 is inherited from main, not produced by this branch, and I am not pushing a fix for it here.

The two failing jobs both trace to one upstream cause:

required-ci: FAILED PHASE parse (16 error(s))
required-ci: FAILED PHASE namespace-wave-admission (no head index)

namespace-wave-admission did not fail on its own merits — it never ran:

required-ci: namespace-wave-admission NOT RUN — the parse phase did not
produce an index (it refused, or this lane does not own it)

All 16 parse errors are in one file this branch does not touch:

dag/test/claim/emit_copy_qualification_witness_test.dag:483..500:
  source annotation names no subject: no module item follows it.
  Move it above the declaration it describes.

That file is byte-identical to origin/main at this head (git rev-parse HEAD:<path> equals git rev-parse origin/main:<path>), does not appear in git diff --name-only origin/main...HEAD, and was last written by #10390, which left a trailing // block at EOF with no declaration following it — a DESIGN §4c violation, since annotations must be leading blocks attached to a module item.

Three PRs are already open against it — #10414, #10418, #10420 — so the repair is in hand and a fourth would be redundant. This PR is blocked behind whichever lands; I will merge main again and re-run then.

What the run does establish about this branch, in the same log:

  • required-floor: verdict=FloorClean unexpected_failures=0, with planned=3645 executed=3645 not_attempted=0 terminal=3645, claims_failed=0;
  • all 24 changed witnesses in test.claim.scm_role_requirement_integration_witness report standing=planned-and-passed … outcome=passed;
  • heal-generated-artifacts: success and required-witnesses-build: success.

So the floor is clean and the renamed module's claims pass; what is missing is the namespace-admission verdict, which cannot be obtained until parse produces an index. I am not treating the floor result as a substitute for that verdict.

— sent from deep-carp-676

…wer named it

Main was red at parse: #10390 left a trailing annotation block at EOF of
emit_copy_qualification_witness_test.dag with no declaration after it, 16 section 4c errors,
which took the head index down and with it the namespace-wave-admission verdict this branch
actually needs. Repaired on main; merged here. I filed nothing against it -- three PRs were
already open on that file.

The ledger entry for my own three verification bugs is rewritten in the reviewer's framing,
which is sharper than what I had. I wrote that an index which can be incomplete must be able
to say so. The precise statement is that A PARTIAL OBSERVER RETURNED THE NEGATIVE VALUE OF A
TOTAL OBSERVER.

That is the part that makes these dangerous rather than merely incomplete. A parser that
cannot see continuation-joined literals does not report that it failed to read a row -- it
returns the row set without it, the same type and shape a complete parser returns. An index
that does not know coproduct variants does not report that it lacks the form -- it returns
the empty owner set, which is exactly what a total index returns for a spelling nothing
declares. The answer is well formed and of the right type; only the meaning is wrong, and the
caller has no way to tell.

So the obligation sits on the observer, not the caller: anything reading the corpus that can
be partial must be able to say it was partial, or refuse. Three instances on this branch, one
shape -- an empty read from a transliterated path, a non-match from the import path, an empty
owner set from a pattern that did not cover the language.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ4iThiZ1B9LPB9ePr8qa9
@briansrls
briansrls merged commit 25dc75d into main Sep 4, 2026
3 checks passed
@briansrls
briansrls deleted the scm-role-requirement-integration-cut branch September 4, 2026 15:24
@briansrls
briansrls restored the scm-role-requirement-integration-cut branch September 4, 2026 15:33

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVED — exact-head technical ruling

Approved exact head:

01a98bfd1b763c962d5f3bc8aad7af741be2e045

Exact-head workflow 33889253214 completed successfully. required-witnesses-floor, required-witnesses-build, heal-generated-artifacts, and the aggregate witnesses job all succeeded. The floor reached and completed its adjudication, so the third roster resolution is established by the production namespace predicate rather than the weaker hand join; the parse-short-circuited result on 3c6e095 is superseded.

The PR body no longer carries a mutable tense-bearing CI verdict and instead names the checks list as the live instrument. The final head includes main's parse repair and records the partial-observer failure class without changing the accepted role-requirement-integration implementation.

No implementation, authority, evidence, roster, conflict-resolution, generated-artifact, or CI objection remains on this SHA.

GitHub had already squash-merged the PR as 25dc75d917ea4ec911532abfe4c4be023b008b29 before this review was submitted, so this review records the exact-head technical approval; it did not authorize an already completed merge.

gunbai-bot Bot pushed a commit that referenced this pull request Sep 4, 2026
…e module emit-core hosts can reach the authority it asks

Main parses again at 159421d (#10428 re-attached the annotation #10390 orphaned),
so this is the one integrate-main push, carrying the build repair with it.

THE BUILD FAILURE THIS FIXES, AT ITS ROOT RATHER THAN AT ITS SYMPTOM.
v1_compiler_emit_core_support is compiled TWICE from one file: once inside
v1-compiler, where crate::v1_compiler_parse resolves, and once inside
v1-stage0-emit-core via #[path], where the crate root offered eight modules and
parse was not one of them. Its reachable set is the INTERSECTION of two crate
roots, so consuming the parser's single authority for "is this item a resource"
compiled in one and E0432/E0433'd in the other.

The emit-core crate's own generated doc says it exists to host that module
"without copying semantics". The missing name was defeating that: the
alternatives were to FORK the predicate into a module that cannot see the
minting vocabulary it is defined against, or to SCATTER the exclusion across the
call sites. So the boundary was the defect, not the predicate, and the fix is to
make the root set true rather than to work around it.

WHY NOT THE OTHER ARMS, since a reviewer meeting a partition edit inside a
namespace-cut PR should not have to reconstruct this.

  MOVE the predicate down beside Node. Rejected: it is defined NEGATIVELY over
  parse's minting vocabulary -- true if any property's name is not
  "sole_constructor" -- so it is a statement ABOUT that vocabulary, and
  v1.compiler.parse's own note scopes it "complete against the parser's minting
  vocabulary AS OF THIS COMMIT". A definition whose truth is maintained by a
  module it cannot see is a fork with a delay on it.

  APPLY THE EXCLUSION IN THE CALLERS. Rejected on its own measurement. The
  hypothesis was four call sites; the enumeration is 24 call expressions in 12
  functions across v1.compiler.emit_rust (19/9), emit_go, emit_python,
  trait_derive_emit, plus the census reader. Twelve hand-applied exclusions is
  twelve places the next property-minting modifier reintroduces the defect with
  nothing watching -- verbatim the failure parse's note predicts.

WHAT LANDS. v1_compiler_parse joins the v1-infer unit and std_import joins
std-core, chosen for LAYER: parse is a pipeline stage and sits beside
v1_compiler_coercion and the infer modules. parse is a SOURCE in that unit --
nothing there is reachable from it -- so the unit graph gains no edge back, and
validate_partition_r4 adjudicates that mechanically via SccSplit/UnitGraphCycle
rather than by this paragraph. Every generated artifact in the chain was
regenerated through its authority: the roster by the generated-artifact gate,
the stage0 mirrors by --required-regen, the crate manifests and lib roots by
--emit-partition-crates. No hand-edited generated bytes.

THE TRANSITIVE CLOSURE IS THE CHECK, NOT THE IMMEDIATE DEPENDENCIES. An earlier
report of this change said parse depends on eight modules and std_import on two.
That is the immediate set and it passes cleanly on a closure that fails two
levels down. The transitive closure of both seeds is 29 modules; 27 are already
partitioned and the 2 remaining are the seeds themselves, so nothing else is
dragged in -- corroborated independently by the emitter, which drifted three lib
roots and NO Cargo manifest, meaning no new inter-crate dependency was required.

THE ADMISSION ENTRY WAS RE-APPLIED ACROSS THIS MERGE, NOT CARRIED. The
conflicting hunk was a misaligned array head -- this cohort's label line against
the SCM cohort's, with the body below the marker belonging to the other subject
-- so resolving the markers in place would have spliced one cohort's rows onto
another's body. Main's file was taken whole and the delta re-derived at ROW
IDENTITY grain against the merge base: 2 added here, 0 removed, against main's
29 additions and 254 removals. Merged array is 32 rows, no row of either side
dark. The entry is renumbered TWENTY-THIRD and its citation of the
now-dissolved twenty-sixth entry repointed, because #10355 deleted the entry it
named.

Verified by execution on the merged tree, not by inspection: cargo build green
with the repair present and reached, cargo clippy --all-targets -D warnings
clean, and compiler_tests::a_resource_item_is_not_read_as_a_type_item passing
with its positive control, resource discriminator, sole_constructor
over-correction guard and two-reader agreement assertion.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018vz8ESEVFC7Cox1xAaXudg
gunbai-bot Bot pushed a commit that referenced this pull request Sep 4, 2026
… converge() this change removes

One conflicted path, dag/gunbc/repo/repo_ruleset.dag, resolved to preserve BOTH
authorized deltas rather than by taking a side:

- #10378's contention-rate annotation (its first hunk) auto-merged untouched.
- #10378's SECOND delta was deleting three dead `String` rows --
  repo_ruleset_converge_entry / _converge_function / _verify_function. That is the
  §4c prose-as-data cleanup this branch had identified and routed to MAIN-Q; it
  landed there first, so the deletion is taken and the two rows this branch still
  carried are gone.
- This branch's world_* handler restructuring is kept whole.

MAIN'S "VERIFY IS READ-ONLY AND CONVERGE WRITES" NOTE IS DROPPED, and that is the one
resolution that is not mechanical. It describes two entry points; this change deletes
the mutating one along with apply_desired_ruleset, so after the merge the file declares
`verify()` and nothing else, and nothing in the tree cites `apply_desired_ruleset` or
`repo_ruleset_converge_function`. Keeping the note would leave a §3 citation of a symbol
that no longer exists -- a note is not preserved by being carried, only by staying true.

THE ROSTER ORDINAL IS RENUMBERED TWENTY-FIRST -> TWENTY-THIRD, which the merge forces and
a grep would have hidden. Main's highest transition is now TWENTY-SECOND (#10355), so
TWENTY-FIRST follows nothing. It is also not free for the taking: #10355 was itself
numbered twenty-first on an earlier head and renumbered rather than reused, so that a
citation of "the twenty-first entry" would not resolve to two rows across time. An
abandoned ordinal and an unused one are indistinguishable by counting, so the vacancy is
a trap rather than an invitation.

The consumed-row obligation is discharged by main's own deletion: the roster goes
258 -> 33 rows, being main's 31 plus this change's 2, which is exactly the blocker run
33889309585 reported (255 consumed admissions due on a roster-touching change) while its
floor read FloorClean with claims_failed=0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015EdHQ244XXdBKRKGX6jrV4
gunbai-bot Bot pushed a commit that referenced this pull request Sep 4, 2026
The namespace-wave-admission phase refused with `0 unadjudicated delta(s),
0 stale admission(s), 30 CONSUMED ADMISSION(S) DUE FOR DELETION ON THIS
ROSTER-TOUCH`. The zero/zero half is the good reading -- this branch's own
namespace work is clean. What refuses is the obligation the roster imposes on
whoever touches it next: #10355 is in this branch's base, so its rows are
satisfied at the base, and a consumed row comes due on the roster's own next
touch. This change touches it.

ADJUDICATED BY THE DECLARING-MODULE JOIN, NOT BY THE TRIGGER SENTENCE, because
the entry being retired says in terms that a trigger sentence is not evidence
the trigger fired. Each row was joined against MAIN's tree by its own
(module, in_declaration, spelling, target) tuple: 30 of 30 name a spelling
DECLARED in gunbc.scm.proposal, none open. Rows checked equals rows in label
equals the count the wall reported -- 30 = 30 = 30 -- so the subject was not
silently narrowed by a parser that could not see some of it.

ONE OF THIS FILE'S TWO RECORDED JOIN FAILURE MODES ACTUALLY FIRED. RequireBinding
and RequireBindingAbsent are COPRODUCT VARIANTS rather than data/fn/type
declarations, so a declaration index reading only line-start declarations would
have answered "not found" for both -- indistinguishable from "not declared",
which is precisely the defect the TWENTY-NINTH DISSOLUTION records catching on
its second pass. The join resolves variants and fields as well as declarations,
and it was CALIBRATED rather than trusted: MergeCommit, ObjectStore and a
fabricated name all answer NOT DECLARED against the same module, so a uniform
"found" was not available to it.

The two gunbc#10350 kernel-identity rows REMAIN. They are not consumed: this
PR has not merged, so the base does not carry the relocation and the deltas are
still producible. Their own deletion is owed to the first roster-touch after
this lands, by the same join.

SCM_PROPOSAL_VOCABULARY_LABEL is deleted with its rows, and the cohort's entry is
retitled as the THIRTIETH DISSOLUTION recording the adjudication, including what
the hand join does NOT establish: it is a necessary condition only, since
admission_consumed_at_base resolves the full subject through the re-export chain
and requires an exact singleton, which no hand join reproduces. The wall's own
run at the exact head is the proof.

The remaining required-witnesses-floor red is NOT addressed here and is not this
branch's: STALE-QUARANTINE on
test.claim.declared_type_expected_type_path_witness, inherited from #10402
landing a wall without retiring the expected-red row it greened. It is owed a
standalone repair; carrying it here would put main's recovery inside a feature
PR that is separately blocked on review.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018vz8ESEVFC7Cox1xAaXudg
gunbai-bot Bot pushed a commit that referenced this pull request Sep 4, 2026
…ons this change came due on

NOT A JUDGEMENT CALL, AND NOT MY COHORT. The required namespace-wave-admission phase reported them
by identity on this branch's head -- 30 of 30 `CONSUMED ADMISSION`, all the gunbc#10355 SCM
proposal-vocabulary rows -- with `0 unadjudicated delta(s), 0 stale admission(s)`. #10355 has merged,
the base binds each spelling to `gunbc.scm.proposal`, and the deltas have stopped being producible.
`SCM_PROPOSAL_VOCABULARY_LABEL` goes with them, since nothing cites it once the rows are gone.

WHY A PR ABOUT FN-ARROW REACHABILITY IS DELETING SCM VOCABULARY ROWS: the roster's standing rule is
that a consumed row's deletion comes due on the roster's NEXT TOUCH, whoever touches it. That rule is
the only thing keeping an append-only ledger from growing without bound, and it only works if the
lane that touches the file pays it rather than passing it on. This change touches the roster, so it
pays. The ledger is now 3 rows: this PR's 2 and one other.

THE OTHER FLOOR FAILURE ON THAT SAME RUN IS NOT ADDRESSED HERE BECAUSE IT IS NOT A DEFECT.
`TERMINAL-LEDGER REFUSAL cause=WireAuthorityUnresolved ... MemoryStallRefusedPageThrash` is the floor
refusing a runner that refaulted its own evicted pages at 263455 major faults/minute while computing
for 4% of the wall. That is the machine failing to deliver the admitted budget, reported as a typed,
located refusal rather than a silent slow green -- the mechanism working. It is retry-eligible and
nothing in this diff moves it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ
gunbai-bot Bot added a commit that referenced this pull request Sep 4, 2026
… of above the module that had to re-spell it (#10350)

* Home the kernel-identity authority beside the minter it asks, instead of above the module that had to re-spell it

XL-0B's first constraint, discharged. gunbc.type_reference_decl_file_occurrence_census's
kernel-minted-provenance row states it: the KernelMinted arm must be DERIVED from
resolved_node_is_kernel_identity_for_name rather than re-spelled, "because a fifth prefix
test would add an authority while claiming to remove four."

THE FORK WAS POSITIONAL. v1.compiler.infer_env DECLARED that predicate and never called it.
The module that mints the span it tests -- v1.std.core, whose kernel_span synthesizes
"<kernel:NAME>" -- cannot import infer_env without closing a cycle, so
declaration_provenance_of re-derived the same comparison in place. One fact, two spellings,
for no reason but where the declaration sat. The predicate now lives in v1.std.core beside
kernel_span, and declaration_provenance_of reads it.

AND THE SPELLING IT REPLACED WAS THE WEAKER ONE, which the census had not counted. The
infer_env body inlined concat("<kernel:", name, ">"), reproducing kernel_span's output by
hand -- so it was a second authority for the span FORMAT as well as for the identity
question. The relocated body asks kernel_span. Editing that format used to leave the
recognizer answering the old shape with no refusal anywhere; that divergence now has no
constructor.

EVIDENCE, BOTH DIRECTIONS, BY EXECUTION.
ct_kernel_identity_single_authority_test runs in the required rust-unit-tests job under
`cargo test --release -p v1-compiler --lib`. Green as authored. Red under exactly the
mutation it exists to catch -- exact equality replaced by a "<kernel:" prefix test -- failing
on the discriminating row (a node carrying a kernel span for a DIFFERENT name), with a
positive control that stops that row being satisfied by a predicate that had simply stopped
answering true. Enrolled per DESIGN 4b(4): the climb keeps its discriminating red.

That suite is RED ON MAIN independently of this change -- 16 failed / 728 passed on an
unmodified tree at e5a51d6, measured by running the identical command on a clean
checkout before attributing anything here. The failures are host/index-sensitive
(schedule_retention, regen_round_cost, required_floor) and are not touched by this diff.

SCOPE, STATED SO THE LARGER HALF IS NOT READ AS DONE. This discharges the FIRST of the two
constraints the census names. The second is untouched and is bigger: CorpusDeclared still
carries decl_file as a position, so the DeclarationCarrier half std.repair_input_origin
explicitly defers to XL-0B/C is still owed. Both ledger rows are updated to say so and to
cite the predicate at its new home rather than at the stale (and, in state_space_conflation,
never-existent "v1.compiler.env") one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018vz8ESEVFC7Cox1xAaXudg

* Escape the quotes in the census row's prose so the module index can parse it

The XL-0B receipt I appended to gunbc.type_reference_decl_file_occurrence_census quoted the
spelling it was retiring -- concat("<kernel:", name, ">") -- with RAW double quotes inside a
.dag String literal, which terminates the string and makes the source unparseable. The module
index then refuses the whole corpus, so heal-generated-artifacts could not index the tree and
never reached the regeneration the design-ledger carve-out delegates to it.

The file already uses the escaped form for exactly this; the added row now matches it.

AND THE DIAGNOSTIC'S LOCATION IS A BYTE OFFSET WEARING A LINE NUMBER'S CLOTHES. It reads
`dag/gunbc/type_reference_decl_file_occurrence_census.dag:15713-15714`, and that file is 526
lines in every tree -- main, this head, and the merge result. 15713 is the BYTE offset of the
opening quote of the broken literal. So the span is correct and its RENDERING sends every reader
to a line that does not exist. Filed separately rather than fixed here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018vz8ESEVFC7Cox1xAaXudg

* Emit the assertion message with a positional placeholder: {name} interpolates in a .dag string

The emitter row I added spelled its Rust assertion message with an inline format capture,
`{name}`. Inside a .dag String literal that brace form is INTERPOLATION, so the compiler resolved
a variable `name` that does not exist in ct_kernel_identity_single_authority_test and refused the
v2 self-compile. The bare `{}` placeholder already used elsewhere in this file does not
interpolate, so the message takes an explicit argument instead.

THIS ERROR WAS HIDDEN BEHIND THE PARSE REFUSAL and is the reason the whole-corpus pass matters:
while the module index refused to build, nothing downstream ran, so a second defect in a different
file sat invisible behind the first. Two sequential whole-tree runs were needed to see both, and
neither is visible to a cargo build of the seed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018vz8ESEVFC7Cox1xAaXudg

* File the mislocated-span class: a located refusal that renders a byte offset as a line

Filed at the manager's request after gunbc#10350's module-index refusal cited
dag/gunbc/type_reference_decl_file_occurrence_census.dag:15713-15714 in a file that is 526 lines
in every tree. The span was CORRECT: 15713 is a byte offset, and the path was right. Only the
rendering was wrong, and 'path:N-M' declares no unit, so the reader cannot tell which they hold.

WHY IT EARNS A ROW RATHER THAN A FIX AT THE SITE. The reader who hit it did the correct diligence
-- checked the cited file in main, the PR head and the merge result, confirmed it is not a
generated artifact, declined to guess -- and was defeated anyway, authoring two candidate
mechanisms (wrong path attribution, corpus-global line index) that were both false and neither
eliminable from the log. A diagnostic that defeats correct diligence is the subject, not the
quoting bug that surfaced it.

It is the fabricated-plausible-output shape applied to a diagnostic's own span, and it is worse
than an unlocated refusal rather than better: an unlocated refusal makes the reader search and
they know it, while a confidently mislocated one makes them doubt the path and the tool.

CEILING is rung 4 and the class is decidable, so the row names the capability rather than an
artifact: a span type whose constructors distinguish byte offsets from line-column positions, with
renderers deriving format from the constructor. That is a change to the span carrier and every
renderer, so it is filed at the grain it must be repaired at rather than patched where it appeared.

Carrier only -- docs/design-failure-modes.md is authored by heal per gunbc.generated_artifact's
HealRegeneratesAfterProvisionalMerge carve-out. Appended at the END of the roster, per its own
source-order rule.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018vz8ESEVFC7Cox1xAaXudg

* Cite jolly-ferret's sibling instance: two right-value wrong-rendering diagnostics in one night

gunbc#10352 found the floor rendering cost=500ms EXACT from an integer-truncated nanosecond
measurement -- comparison correct, refusal correct, rendering defective, and it recruited auditors
into filing against the comparator. Same shape as this row's byte-offset-as-line, reached from an
unrelated subject by a reader who was not looking for it.

Two independent instances is what makes the operative rule worth stating: WHEN A LOCATED
DIAGNOSTIC POINTS SOMEWHERE IMPOSSIBLE, DISTRUST THE UNITS BEFORE THE LOCATION.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018vz8ESEVFC7Cox1xAaXudg

* chore: regenerate drifted generated artifacts (ci auto-heal)

* Regenerate both levels of the compiler-tests emitter chain, in the order the chain forces

The regen drift was mine and it was TWO levels, not two files.

LEVEL 1 -- v1_compiler_compiler_tests_rust.rs. I added ct_kernel_identity_single_authority_test to
src/v1/compiler_tests_rust.dag and never wrote that module's own generated twin. It now carries the
new emitter function and its entry in ct_coercion_tests's concat chain.

LEVEL 2 -- compiler_tests.rs. Its only difference from the emitter's output was the POSITION of the
test: I hand-inserted it before shaped_type_node, the emitter appends it at the end of
ct_coercion_tests. Verified as a pure move rather than a content change -- the two files have an
IDENTICAL MULTISET OF LINES and equal byte length, differing only in order.

THE ORDER OF THE TWO PASSES IS FORCED AND THE NAIVE FIX IS SILENTLY DESTRUCTIVE. compiler_tests.rs
is emitted by the seed's COMPILED-IN emitter, so a first-pass candidate is produced by the emitter
as it was BEFORE this change -- it cannot emit a test it does not know about. That candidate was 134
lines short, exactly the size of the test, and copying it would have DELETED the enrolled RED while
satisfying the drift check: a green PR whose discriminating probe no longer exists.

So: pass 1 installs the emitter's own mirror, the seed is REBUILT so the emitter knows the test, and
pass 2 produces a compiler_tests.rs that contains it -- 4521 lines, matching, with the test present.

Checked rather than assumed: both files are byte-identical to their pass-2 candidates after
cargo fmt, so formatting cannot re-introduce drift; the test and its discriminating assertion are
present in the committed bytes.

Regenerated on top of ce937d0, merged first because #10282 reshapes the marshal and a candidate
computed on the older base could have been bytes that fight it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018vz8ESEVFC7Cox1xAaXudg

* chore: regenerate drifted generated artifacts (ci auto-heal)

* chore: regenerate drifted generated artifacts (ci auto-heal)

* Adjudicate the relocation's two binding deltas by name, and stop the emit side reading a resource as a type

TWO SEPARATE THINGS LAND TOGETHER BECAUSE CI IS THE BINDING CONSTRAINT, not because they are one
change: the wave-admission rows this PR's own relocation requires, and the emit-side repair the
type-occurrence census refusal pointed at.

-- THE ADMISSION ROWS --

required-ci refused with `namespace-wave-admission (2 unadjudicated delta(s), 0 stale admission(s),
16 consumed admission(s))`. The two deltas are this PR's whole content:

  TargetChanged binding v1.compiler.infer::ancestry_binding_is_kernel_identity
  TargetChanged binding v1.compiler.emit_rust::import_name_resolves_to_host_realized_kernel_scalar

both for `resolved_node_is_kernel_identity_for_name`, base {v1.compiler.infer_env} -> head
{v1.std.core}. A relocation MUST produce TargetChanged bindings; the wall refusing until someone
says so out loud is the wall working. They are UNADJUDICATED, not unadjudicatable.

Adjudicated at full identity grain -- module, in_declaration, spelling, target -- one row per delta,
so the count goes 2 -> 0 by naming both subjects and not by widening. A third delta of the same
shape still refuses, which is what makes this distinguishable from erasing the subject.

The rows are born with their own death declared: when this merges, base and head both carry the
relocation, no run can produce these deltas, and both go STALE -- which reds every unrelated PR.
The trigger beside them says explicitly not to trust itself: join each row against MAIN'S tree on
its own tuple, and assert rows-checked equals rows-in-label, because a path guessed from a module
path reads empty and empty reads identically to "the binding is absent" -- the mechanism that
nearly carried 128 rows wrongly on the twenty-sixth entry.

-- THE EMIT-SIDE REPAIR --

The activation-revision recensus refused: CensusUnavailable { cause: DeclarationDomainDisagrees },
two occurrences, `dag/std/resources.dag::Network` and `::AuthContext`. The cause was already
authored in the tree. v1.compiler.parse's classifier gained a resource arm, dropping divergence from
202 items across 100 modules to these two, and its note ends: "Repairing the emit-side shape
predicates is a change to a different authority and is deliberately not smuggled in here." This is
that repair.

Those two resources declare NO capabilities, so they carry no children, no body, no params and no
connective -- they ARE bare leaves by shape, so the emit side read them as type items while the
parser read them as resources. Not instrument-only: all three emitters test is_type_decl_item BEFORE
is_resource_def_item, so both were EMITTED AS TYPE DECLARATIONS and the resource arm was unreachable
for them.

The exclusion DERIVES rather than re-spelling: is_type_alias_item and is_type_decl_item ask
v1.compiler.parse parsed_item_carries_resource_entries, the same single authority the parser asks,
so "what a resource item is" has one definition and these are two consumers of it. Spelling the
shape again here is what produced the divergence.

NOT PLACED IN is_bare_leaf_item, which would have been one site instead of two: that predicate is a
statement about SHAPE, a capability-less resource genuinely IS a bare leaf, and it has consumers
outside these arms whose meaning depends on its params-count claim -- narrowing it would have
silently changed alias hopping instead of resource classification.

AND NOT REPAIRED BY REORDERING THE CHAIN, which would also have greened the census. is_resource_def_item
still COUNTS properties -- the shape parse already had to fix -- so it would claim any sole_constructor
type, masked today only because the type arms run first. Reordering would have ARMED that over 202
items while turning the instrument green. That dormant defect is filed as the failure-mode row
dispatch_correctness_resting_on_arm_order: mitigatable today, ceiling structurally impossible, and
its next-rung trigger names the CAPABILITY -- a positive item kind carried on the emit side, so
dispatch derives as an exhaustive match and cannot be order-sensitive.

-- EVIDENCE --

The enrolled test asserts the composite the census actually joins on -- is_type_def_item OR
is_type_alias_item OR is_type_decl_item -- and not one arm. An earlier draft asserted
is_type_decl_item for a property-free bare leaf and went RED: with no inferred type such an item
reads as a type ALIAS. It is still a type item; the arm was the wrong subject, and a control that
had passed by luck would have shipped a test measuring something other than the refusal.

Four rows: the positive control, the resource discriminator (removing the exclusion turns it true),
an over-correction guard asserting a sole_constructor-only item is STILL a type item so the
exclusion can never be re-spelled as a property count, and a reader-agreement equality that fails
from either side.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018vz8ESEVFC7Cox1xAaXudg

* Restore the generated mirrors from this branch's side so the tree compiles before regeneration

Taking main's side of the four generated artifacts during the merge was wrong in a way the merge
itself could not show. v1_compiler_emit_rust.rs on main still calls
crate::v1_compiler_infer_env::resolved_node_is_kernel_identity_for_name -- the symbol THIS BRANCH
MOVED to v1.std.core -- so the merged tree did not compile, and a tree that does not compile cannot
be regenerated. The plan 'take theirs, regen will supply the truth' has a precondition I did not
state: regen must be able to BUILD, and the file breaking the build was the one waiting to be
regenerated.

Restored all four from this branch's pre-merge head, which is a compiling tree. These bytes are
still not authored on either side and are not the answer -- they are a build-able starting point so
the regeneration can produce the real ones from the merged .dag authorities, which carry both this
branch's relocation and main's changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018vz8ESEVFC7Cox1xAaXudg

* Bootstrap the emit mirror to a tree that compiles: main's bytes plus this branch's three-substitution delta

NEITHER SIDE OF v1_compiler_emit_rust.rs COMPILES AGAINST THE MERGED TREE, which is why two regen
attempts died at 127 with no regeneration running at all. Main's copy calls
crate::v1_compiler_infer_env::resolved_node_is_kernel_identity_for_name -- the symbol this branch
moved -- and fails E0432. This branch's copy predates main's call-arity change and fails E0061. The
file that must be regenerated is the file preventing the build that produces the regenerator.

Broken by applying THIS BRANCH'S DELTA to MAIN'S BYTES, counted rather than eyeballed: three
substitutions, each asserted to occur exactly once before replacement -- drop the spelling from the
v1.compiler.infer_env re-export list, add it to the v1.std.core import list in the slot this branch
uses, repoint the single call site. Post-conditions asserted: zero stale references remain, exactly
one repointed reference exists. The re-wrap that follows is cargo fmt's, not mine: the pre-commit
hook refused the hand edit until the import list was re-wrapped, which is the hook catching exactly
the class of damage hand-editing a generated file does.

The other three generated artifacts are taken from main verbatim, because none references the moved
symbol and none needs a delta to build. Confirmed rather than assumed for compiler_tests.rs, which
is the one that could have.

THESE BYTES ARE A BOOTSTRAP, NOT THE ANSWER. The regeneration that follows overwrites all four from
the merged .dag authorities. If the regenerated bytes differ from these, the regenerated ones are
right.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018vz8ESEVFC7Cox1xAaXudg

* chore: regenerate drifted generated artifacts (ci auto-heal)

* Install the regenerated stage0 mirrors, and confirm the bootstrap reproduced the generator exactly

The four generated artifacts now carry what --required-regen emits from the merged .dag authorities,
produced by the forced two-pass order: install the emitter's own mirror, REBUILD so the emitter knows
the new test, then regenerate the file it emits. A single pass emits compiler_tests.rs from the
PRE-EDIT emitter, which cannot know a test that was just added.

THE BOOTSTRAP WAS EXACT, AND THAT IS A RESULT RATHER THAN AN ASSUMPTION. v1_compiler_emit_rust.rs is
ABSENT from this commit: the regenerated bytes are identical to the hand-applied bootstrap, so the
three counted substitutions reproduced the generator's output precisely. Had they differed, the
generator's bytes would have won and this commit would say so.

VERIFIED BY EXECUTION, NOT BY COMPILE: cargo test --release -p v1-compiler --lib on the regenerated
tree runs a_resource_item_is_not_read_as_a_type_item and it PASSES. The over-correction guard -- a
sole_constructor-only item must still read as a type item -- is present in the emitted bytes, so the
exclusion cannot be silently re-spelled as a property count without this going red.

Both files are byte-identical after cargo fmt, so formatting cannot re-introduce drift.

docs/design-failure-modes.md is deliberately NOT updated here. --required-regen does not emit it --
a run where all four .rs mirrors installed cleanly produced no projection candidate at all -- because
that artifact is heal's under the design-ledger carve-out. The tree therefore lands
authority-ahead-of-artifact on that one file BY DESIGN: the roster carries 101 rows and the
projection 99. That is the state heal repairs and the generated-artifact gate can see. The state
nothing downstream can see -- a row deleted -- was checked for by set difference against main and is
absent.

THE 16 SUITE FAILURES ARE MAIN'S, ESTABLISHED BY AN IDENTITY JOIN AND NOT BY A COUNT. Two trees on
one runner, preconditions asserted before the comparison was trusted: the patch present in one
(4 references) and absent in the other (0), and the two tree shas required to differ. Failing test
NAMES compared as sets: mine MINUS main is EMPTY, main MINUS mine is EMPTY. An earlier attempt at
this join was VACUOUS -- both arms silently measured the same tree, which guarantees identical sets
by construction and looked exactly like the answer. Two sets of sixteen can be disjoint, so the
count match established nothing on its own.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018vz8ESEVFC7Cox1xAaXudg

* chore: regenerate drifted generated artifacts (ci auto-heal)

* chore: regenerate drifted generated artifacts (ci auto-heal)

* Retire the 30 consumed gunbc#10355 admissions this roster-touch owes

The namespace-wave-admission phase refused with `0 unadjudicated delta(s),
0 stale admission(s), 30 CONSUMED ADMISSION(S) DUE FOR DELETION ON THIS
ROSTER-TOUCH`. The zero/zero half is the good reading -- this branch's own
namespace work is clean. What refuses is the obligation the roster imposes on
whoever touches it next: #10355 is in this branch's base, so its rows are
satisfied at the base, and a consumed row comes due on the roster's own next
touch. This change touches it.

ADJUDICATED BY THE DECLARING-MODULE JOIN, NOT BY THE TRIGGER SENTENCE, because
the entry being retired says in terms that a trigger sentence is not evidence
the trigger fired. Each row was joined against MAIN's tree by its own
(module, in_declaration, spelling, target) tuple: 30 of 30 name a spelling
DECLARED in gunbc.scm.proposal, none open. Rows checked equals rows in label
equals the count the wall reported -- 30 = 30 = 30 -- so the subject was not
silently narrowed by a parser that could not see some of it.

ONE OF THIS FILE'S TWO RECORDED JOIN FAILURE MODES ACTUALLY FIRED. RequireBinding
and RequireBindingAbsent are COPRODUCT VARIANTS rather than data/fn/type
declarations, so a declaration index reading only line-start declarations would
have answered "not found" for both -- indistinguishable from "not declared",
which is precisely the defect the TWENTY-NINTH DISSOLUTION records catching on
its second pass. The join resolves variants and fields as well as declarations,
and it was CALIBRATED rather than trusted: MergeCommit, ObjectStore and a
fabricated name all answer NOT DECLARED against the same module, so a uniform
"found" was not available to it.

The two gunbc#10350 kernel-identity rows REMAIN. They are not consumed: this
PR has not merged, so the base does not carry the relocation and the deltas are
still producible. Their own deletion is owed to the first roster-touch after
this lands, by the same join.

SCM_PROPOSAL_VOCABULARY_LABEL is deleted with its rows, and the cohort's entry is
retitled as the THIRTIETH DISSOLUTION recording the adjudication, including what
the hand join does NOT establish: it is a necessary condition only, since
admission_consumed_at_base resolves the full subject through the re-export chain
and requires an exact singleton, which no hand join reproduces. The wall's own
run at the exact head is the proof.

The remaining required-witnesses-floor red is NOT addressed here and is not this
branch's: STALE-QUARANTINE on
test.claim.declared_type_expected_type_path_witness, inherited from #10402
landing a wall without retiring the expected-red row it greened. It is owed a
standalone repair; carrying it here would put main's recovery inside a feature
PR that is separately blocked on review.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018vz8ESEVFC7Cox1xAaXudg

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 5, 2026
…ranch's next touch

All 22 `gunbc#10445` rows are deleted -- 17 object-table codec-move and 5 semantic-target
constructor -- along with both label consts. Reported by identity as `CONSUMED ADMISSION`, 22 of 22,
by the required namespace-wave-admission phase on this branch's own head: #10445 has merged and none
of the deltas is producible against the base any more.

RUNNING TOTAL ON ONE BRANCH: 30 (#10355) + 2 (#10350) + 6 (#10439) + 22 (#10445) = 60 rows dissolved
for four cohorts, none of them this PR's, because every sync with main is a roster touch and a
consumed row's deletion comes due on the touch.

THE RATE IS THE OBSERVATION, not the payments. Four cohorts became consumed inside one open branch's
lifetime, which means main is landing roster-touching transitions faster than a branch can finish a
CI cycle. That is not an argument against the rule -- the ledger stands at 2 rows instead of 62
precisely because it is paid on touch -- but it does mean the toll scales with how long a branch
stays open, and the honest way to shrink it is shorter branches, not deferred payment.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ
briansrls pushed a commit that referenced this pull request Sep 5, 2026
…aced, and BOTH are blind at a declaration root (#10300)

* fn_index: the depth-one callee read agrees with the fold_node it replaced, and BOTH are blind at a declaration root

DECIDED BY EXECUTION, both halves.

AGREEMENT: yes, exactly. #10156's `atom_identities_in_node` and the `fold_node`
reader it replaced return the same list on every one of 1777 live fn-arrow
declarations. The old fold's step read `child.node` and DISCARDED `child.atoms`,
so its whole-subtree descent produced immediate-children-only — the annotation's
"extensionally the same function" claim is true. `v2.lens.fn_index_depth_agreement`
is the reconstruction and the verdict; it refuses if the two ever diverge.

SEEDS NOTHING: also yes, and it is not a regression — it is a pre-existing defect
BOTH readers share. `marshal_generic` emits every node as a Conj record carrying
its callee atom as a positional child, so a callee is one level under the body
root only when the body IS that one call; a `let`-block body carries its callees
two or more levels down. Of 1777 declarations, 877 had callees no depth-one read
of `decl.output` could see, and the depth-one reader returned 890 of 8908 subtree
atom identities. `call_reachable_decls` was therefore leaving only the
single-call declarations, and its three consumers — v2.lens.determinism,
v2.lens.effect_reach, v2.lens.live_read_classification — were green over a call
graph with most of its edges missing.

THE FIX: `callees_from_node` reads the new `atom_identities_in_subtree`.
`atom_identities_in_node` is unchanged — depth one is the right grain for the two
lens folds that apply it per node of their own descent, and the wrong grain only
at a root.

WHY NOBODY SAW IT: the fixture had been flattened to match the reader. The
determinism witness carried a note asserting the marshal hoists callee atoms onto
the body root, so the fixture must be flat. That premise is false, and the
accommodation made the reader's grain the check's specification. New rows
`leak_reached_through_a_nested_body_is_found` and
`nested_entry_does_not_reach_a_leak_outside_the_call_graph` hold the real shape;
the first is RED against a depth-one reader and is the only one of the five that
flips, measured by reverting the one line.

Filed as `gunbc.recurring_failure_mode`
`fixture_flattened_to_the_reader_grain_it_should_falsify`.

EVIDENCE, ALL EXECUTED on this tree with a locally built gunbc:
- v2.lens.fn_index_depth_agreement `fn_index_depth_agreement` — exit 0.
- all 5 rows of determinism_transitive_witness green; the mutant (callees_from_node
  back on atom_identities_in_node) reds exactly the nested row.
- all 26 rows of effect_reach_test and live_read_classification_test green,
  including every negative control (severed_mid_hop_is_local_read,
  effect_reach_hermetic_fixture_stays_local_holds, red_control_roster_gate_severed_is_local,
  g2_complete_facts_reachable_home_without_carrier_call_is_local).
- whole-corpus cost unchanged: 1m58s before and after, dominated by the
  fn_arrow_decl_facts_live acquisition.

ALSO REPAIRED, BECAUSE IT BLOCKED REGENERATION: `gunbc.recurring_failure_mode`
carried `absence_classifier_default_bucket` and
`green_reported_over_a_population_the_instrument_does_not_own` twice each,
byte-identical, on main. `main_wet` refuses the module with `duplicate
declaration`, so no lane could regenerate docs/design-failure-modes.md. The
second copy of each is deleted; the roster listed each once, so the projection is
unchanged apart from the new row.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ

* Address review 59534: the atom channel has several senders, so exclude the one that is DECLARED and name the residue

THE FINDING IS CORRECT AND IS OLDER THAN THIS PR. `marshal_generic` emits one
indistinguishable `edge_positional(atom_identity_node(..))` for a call's callee, a
record-constructor spelling, a parameter reference, a nullary variant value and a
string literal. `node_atom_identity_optional` sees one Atom connective in every
case, so reading the atom channel follows more than calls. The depth-one reader
had the same unsoundness on immediate children — `is_path_like_lexeme` is the
scar of it — and the transitive read enlarges the population rather than
introducing the class.

EXCLUDED, FROM DECLARED STRUCTURE: a reference to one of the declaration's OWN
parameters. `FnArrowDecl.params` carries those lexemes, so this is a subtraction
from a declared field, not a shape guess; `v2.lens.effect_reach` already makes it
on its literal channel. `callees_from_node` takes `param_names` and
`call_reachable_decls_go` passes `param_names_of(seed)`. Measured live:
`param_collisions: 2` of 1781 declarations reference a parameter whose lexeme also
names a declaration — two false call edges that no longer exist.

CONTROLS, BOTH NEW AND BOTH EXECUTED:
- a_parameter_reference_naming_a_declaration_is_not_a_call_edge — the entry's body
  references `orphan_fn`, which is both its own parameter name and the name of a
  leaking declaration in the closure. Green; RED against the reader with the
  exclusion line deleted (measured).
- the_same_reference_without_the_parameter_collision_is_a_call_edge — same body,
  same callee, parameter renamed. Green in both arms, so the row above is not
  green by reaching nothing. Only the parameter name differs between them.

THE RESIDUE IS DECLARED, NOT CLAIMED AWAY. Record-constructor spellings, nullary
variant values and non-path literals stay indistinguishable from callees. It is a
structural over-approximation computed AS the answer (DESIGN §5's named
non-instance of the absorbing fallback), it widens toward FINDING more rather than
missing more, and the annotation on `callees_from_node` carries the next-rung
trigger as a CAPABILITY: a fn-arrow body projection in which the callee position is
structurally identified. No fixture can express those senders today — the skeleton
gives them no distinguishing shape — which is why that is a trigger and not a
missing test. It is the subject of the parent lane (cool-fox-470).

ALSO, §3: `param_names_of` existed byte-identically in v2.lens.effect_reach and
v2.lens.live_read_classification. Both copies deleted; both import the fn_index one.

All 33 rows green after the change: 7 determinism_transitive_witness, 8
effect_reach_test, 18 live_read_classification_test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ

* Enrol v2.lens.fn_index_depth_agreement as registry infra: it is an instrument, not an enforcing lens

CI on 353f33d failed two required rows and both had one cause: the new module sits
under `v2.lens.` with three path segments, so lens_registry_completeness
classified it a candidate lens and lens_module_gate_holds /
lens_closure_question_zero_holds_live refused it as unenrolled. Reproduced
locally (both returned false), and both return true with this row.

Filed on the known-infra roster rather than as a LensIdV0 entry, because it
enforces nothing: it carries no verdict authority over a production population,
it backs two claims in v2.std.fn_index so they are re-derivable rather than
transcribed, and it reads the whole-corpus acquisition, so it is deliberately not
a floor subject. Nesting the module one level deeper would also have silenced the
gate — `under_nested_prefix` excludes anything past three segments — and that is
the dodge, not the answer: the module would still be an unclassified v2.lens.*
and the gate would be answering about its path rather than its role.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ

* chore: regenerate drifted generated artifacts (ci auto-heal)

* The depth-agreement instrument could not execute: repair its call, its annotation grain, and its cost shape

Review 60130 is CORRECT and the defect was real. This module has never been compiled by anything
-- it is not a floor witness, no phase resolves it, and nothing imports it -- so three independent
breakages accumulated in it silently. That is precisely the inert-lens tier DESIGN section 6 warns
about, arriving in the evidence for a claim rather than in the claim.

1. THE CALL SHAPE. gunbc#10245 made the subject caller-named: `fn_arrow_decl_facts_live` takes
   `pool_roots` and `pool_files`, and the zero-arity form was deleted. The instrument still called
   it with no arguments, so every number this PR cites as re-derivable was in fact transcribed.
   It now declares `agreement_pool_roots = ["dag", "src/v2"]` -- the two roots the required lanes
   pass -- and names them at the call site. The annotation that called it "the zero-arity whole-tree
   acquisition" is corrected too, since it asserted the deleted shape.

2. THE ANNOTATION GRAIN. A record field whose value sat on the following line failed to parse, and
   the resulting resolve failure reported itself as sixteen "source annotation names no subject"
   errors -- a cascade, not the cause. Fixed at the cause.

3. THE COST SHAPE. The call-channel reader added here first collected callee lexemes into a list and
   deduplicated with a linear scan inside a per-node fold, which is quadratic over a 60k-node corpus
   and did not terminate in twenty minutes. DESIGN section 6's bare-minimum-cost rule says a proven
   cost-shape defect is always fixed, instrument or not. It is now an Int count.

WHAT THE CALL-CHANNEL COUNTERS ARE FOR. Review 60065 asks for `callees_from_node` to move off the
whole-subtree atom scan and onto `node_is_call` / `call_callee_target`. Swapping a loud
over-approximation for a silent under-approximation would be strictly worse under DESIGN section 5,
and only execution can say which this would be, so `channel_call_shaped_total` counts how many nodes
of a live fn-arrow skeleton `node_is_call` accepts at all and `channel_callee_total` how many yield a
callee. The measurement is running; the answer goes on the PR, not into prose.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ

* A one-declaration probe for the call channel, because review 60065's question is structural

Review 60065 asks that `callees_from_node` move off the whole-subtree atom scan and onto
`node_is_call` / `call_callee_target`. Answering it needs one fact first: does the call channel see
anything at all on a LIVE fn-arrow skeleton? If it saw nothing, the switch would trade a loud
over-approximation for a reader that is green by construction, which DESIGN section 5 makes strictly
worse, and no corpus-wide tally would be needed to say so.

`first_decl_channel` answers that at a thousandth of the cost of the corpus tally, and its first
answer was uninformative in a way worth keeping in the code: the corpus's first declaration is `add`,
five nodes, calling nothing, so both readers report zero and the comparison discriminates nothing.
The guard is therefore the first declaration the ATOM reader finds callees in, since only there does
a zero from the channel mean a lost edge.

MEASURED: `no_raw_lifecycle_string_survivors_remain`, two subtree nodes, atom_callees 1,
call_shaped 1. The channel is NOT blind on this substrate. That refutes the cheap disposal of
review 60065 and makes the corpus-wide comparison the deciding measurement, which is now running.

Also here, and the reason the corpus tally is not simply left as it was: the resolved-callee half is
now gated on the call-shaped half. `call_callee_target` builds a diagnostic-carrying result per node,
and calling it on all 60k nodes ran 35 minutes at 9.8GB without finishing -- on a shared 64GiB slice
that is a hazard to other sessions, not just a slow instrument.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ

* The merge re-added 255 rows main deliberately deleted, and enforce the two claims the verdict left inert

TWO DEFECTS, ONE OF THEM MINE FROM A MERGE AND INVISIBLE TO GIT.

THE ROSTER. main's TWENTY-NINTH DISSOLUTION (gunbc#10355) deleted all 255 `gunbc#10358`
selector-reclass rows AND the `OLLAMA_CHOICE_RECLASS_LABEL` const they cite, on the roster's own
consumed-row rule. My branch carried those rows from an earlier merge, so the textual merge unioned
them back in while main's deletion of the const won -- 255 rows referencing a name that no longer
exists, reported by the required build lane as 255 `cannot find value` errors. Git flagged nothing,
because a union re-adding a DELIBERATE deletion is a clean merge by every textual measure; only the
deleting commit's own prose says the rows were consumed. The roster is now main's 31 rows plus this
PR's 2, verified by label set difference in both directions rather than by count.

THE VERDICT, which review 60220 found. `fn_index_depth_agreement` computed four numbers and enforced
two. `root_callees_lost_to_depth_one` and `param_collisions` -- claims two and three, the ones that
justify this PR's change at all -- were printed and checked by nothing, which is specification
without execution sitting inside the instrument built to answer exactly that charge.

Both now refuse at ZERO, and the direction is the point: if no live declaration hides a callee below
depth one, #10156's reader was adequate and this PR's change to `callees_from_node` bought nothing;
if no live declaration references its own parameter by a lexeme that also names a declaration, the
parameter exclusion excludes nothing and is dead code defended by prose. Either zero falsifies the
PR rather than the corpus.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ

* chore: regenerate drifted generated artifacts (ci auto-heal)

* Decide review 60065 by execution: the call channel loses 39% of the edges the atom reader finds

MEASURED, over a stated 150-declaration prefix of the live corpus, via
`v2.lens.fn_index_depth_agreement.bounded_channel_compare`:

  compared 150 | atom_callee_total 444 | channel_callee_total 271
  channel_fewer 68 of 150 | channel_none_atom_some 21 of 150

So routing `callees_from_node` through `node_is_call` / `call_callee_target` -- what reviews 60065
and 60220 ask for -- would drop 173 of 444 callee edges, find FEWER on 45% of declarations, and go
COMPLETELY BLIND on 14% of them. That is a silent under-approximation in a REACHABILITY walk, where
a missed edge means a declaration is reported unreachable and eligible for deletion. DESIGN section
5 ranks that strictly below the loud over-approximation it would replace: the atom reader's residue
is extra edges, which keep dead code alive; the channel's residue is missing edges, which delete
live code. I am not making that trade on the strength of the carrier existing.

WHAT I AM NOT CLAIMING. Not that the reviews are wrong about the destination -- the call channel IS
the canonical carrier and the atom scan IS a parallel representation under section 3. What the
measurement shows is that the channel is not yet complete over the live fn-arrow skeleton, so the
move is blocked on the marshal, not on willingness. The rung honesty in `callees_from_node` stays
"can climb now but unbuilt" and now has a number behind it instead of a judgement.

THE REBUTTAL IS ITSELF FALSIFIABLE, which is the part that keeps it from being prose. The verdict
gains a fifth arm that refuses when `channel_none_atom_some` reaches ZERO -- that is, when the
channel stops losing whole declarations. On the day the marshal is reshaped, this instrument goes
RED and says the refusal to switch is stale. A rebuttal that cannot expire is an opinion.

ALSO MEASURED, AND IT BEARS ON THE SAME DECISION: the corpus-wide form of this comparison did not
finish in 85 minutes against a 2-minute baseline for the same tally without it, with
`call_callee_target` already gated behind `node_is_call` and all collection already reduced to Int
counts. The residual 40x is `node_is_call` itself, per node -- a cost the production reader would
import into every consumer of call reachability. Hence a bounded population, stated in the result.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ

* Pay the roster's own rule: delete the 30 consumed gunbc#10355 admissions this change came due on

NOT A JUDGEMENT CALL, AND NOT MY COHORT. The required namespace-wave-admission phase reported them
by identity on this branch's head -- 30 of 30 `CONSUMED ADMISSION`, all the gunbc#10355 SCM
proposal-vocabulary rows -- with `0 unadjudicated delta(s), 0 stale admission(s)`. #10355 has merged,
the base binds each spelling to `gunbc.scm.proposal`, and the deltas have stopped being producible.
`SCM_PROPOSAL_VOCABULARY_LABEL` goes with them, since nothing cites it once the rows are gone.

WHY A PR ABOUT FN-ARROW REACHABILITY IS DELETING SCM VOCABULARY ROWS: the roster's standing rule is
that a consumed row's deletion comes due on the roster's NEXT TOUCH, whoever touches it. That rule is
the only thing keeping an append-only ledger from growing without bound, and it only works if the
lane that touches the file pays it rather than passing it on. This change touches the roster, so it
pays. The ledger is now 3 rows: this PR's 2 and one other.

THE OTHER FLOOR FAILURE ON THAT SAME RUN IS NOT ADDRESSED HERE BECAUSE IT IS NOT A DEFECT.
`TERMINAL-LEDGER REFUSAL cause=WireAuthorityUnresolved ... MemoryStallRefusedPageThrash` is the floor
refusing a runner that refaulted its own evicted pages at 263455 major faults/minute while computing
for 4% of the wall. That is the machine failing to deliver the admitted budget, reported as a typed,
located refusal rather than a silent slow green -- the mechanism working. It is retry-eligible and
nothing in this diff moves it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ

* chore: regenerate drifted generated artifacts (ci auto-heal)

* Pay the roster a second time: the gunbc#10350 kernel-identity rows came due on this branch's next touch

Both `gunbc#10350` kernel-identity predicate-relocation rows are deleted, and
`KERNEL_IDENTITY_RELOCATION_LABEL` with them. Reported by identity as `CONSUMED ADMISSION`, 2 of 2,
by the required namespace-wave-admission phase on this branch's own head: #10350 has merged, both
`v1.compiler.infer::ancestry_binding_is_kernel_identity` and
`v1.compiler.emit_rust::import_name_resolves_to_host_realized_kernel_scalar` bind
`resolved_node_is_kernel_identity_for_name` to `v1.std.core` at the base, and neither delta is
producible any more.

THIS IS THE SECOND SUCH PAYMENT ON ONE BRANCH AND THAT IS NOT A DEFECT. The previous commit deleted
30 consumed `gunbc#10355` rows; a sync with main then brought in a cohort whose own transition had
merged in the meantime, and the phase came due again. A long-lived branch touches the roster once per
sync and pays whatever the base has consumed since. Passing it on instead is exactly what makes an
append-only ledger grow without bound, so the treadmill is the rule working, not friction to route
around.

The ledger is now this PR's 2 rows and nothing else.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ

* chore: regenerate drifted generated artifacts (ci auto-heal)

* chore: regenerate drifted generated artifacts (ci auto-heal)

* Third roster payment: the gunbc#10439 serving-engine rows came due on this branch's next touch

All six `gunbc#10439` serving-engine launch-vocabulary rows are deleted, and
`SERVING_ENGINE_LAUNCH_VOCABULARY_LABEL` with them. Reported by identity as `CONSUMED ADMISSION`,
6 of 6, by the required namespace-wave-admission phase on this branch's own head: #10439 has merged
and none of the six deltas is producible against the base any more.

THREE COHORTS, NONE OF THEM MINE, ONE AFTERNOON: 30 `gunbc#10355` rows, then 2 `gunbc#10350`, now 6
`gunbc#10439`. Each was consumed by a merge that landed while this branch was open, and a branch that
syncs with main N times touches the roster N times and owes the payment N times.

That is the rule working rather than friction to route around, and it is worth stating because the
tempting reading is the opposite. The alternative to paying on touch is a roster that only grows,
where every stale row refuses unrelated changes and the whole cost lands on whoever touches the file
last. Paying three times in an afternoon is the ledger staying small.

The ledger is again this PR's 2 rows and nothing else.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ

* Read fixture-origin markers at declaration subtree grain (#10365)

Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>

* chore: regenerate drifted generated artifacts (ci auto-heal)

Ledger-Repair-Judged: docs/design-failure-modes.md
Ledger-Rows-Repaired: docs/design-failure-modes.md green_reported_over_a_population_the_instrument_does_not_own
Ledger-Repair-Judged: docs/design-rung-drops.md

* chore: regenerate drifted generated artifacts (ci auto-heal)

Ledger-Repair-Judged: docs/design-failure-modes.md
Ledger-Rows-Repaired: docs/design-failure-modes.md state_space_conflation
Ledger-Rows-Repaired: docs/design-failure-modes.md receipt_subject_surface_outlives_its_own_production_time
Ledger-Rows-Repaired: docs/design-failure-modes.md trigger_satisfied_before_the_row_was_written
Ledger-Rows-Repaired: docs/design-failure-modes.md summary_counters_aggregate_over_a_disposition_set_the_verdict_is_not_in
Ledger-Rows-Repaired: docs/design-failure-modes.md append_only_carrier_whose_serialization_shares_a_merge_region
Ledger-Rows-Repaired: docs/design-failure-modes.md a_live_authority_name_carries_a_superseded_claim
Ledger-Rows-Repaired: docs/design-failure-modes.md witness_that_fails_to_compile_is_absent_rather_than_red
Ledger-Rows-Repaired: docs/design-failure-modes.md instruction_and_subject_resolved_from_different_revisions
Ledger-Repair-Judged: docs/design-rung-drops.md

* chore: regenerate drifted generated artifacts (ci auto-heal)

Ledger-Repair-Judged: docs/design-failure-modes.md
Ledger-Rows-Repaired: docs/design-failure-modes.md reported_required_refusal_does_not_precondition_landing
Ledger-Repair-Judged: docs/design-rung-drops.md

* Fourth roster payment: the 22 gunbc#10445 SCM rows came due on this branch's next touch

All 22 `gunbc#10445` rows are deleted -- 17 object-table codec-move and 5 semantic-target
constructor -- along with both label consts. Reported by identity as `CONSUMED ADMISSION`, 22 of 22,
by the required namespace-wave-admission phase on this branch's own head: #10445 has merged and none
of the deltas is producible against the base any more.

RUNNING TOTAL ON ONE BRANCH: 30 (#10355) + 2 (#10350) + 6 (#10439) + 22 (#10445) = 60 rows dissolved
for four cohorts, none of them this PR's, because every sync with main is a roster touch and a
consumed row's deletion comes due on the touch.

THE RATE IS THE OBSERVATION, not the payments. Four cohorts became consumed inside one open branch's
lifetime, which means main is landing roster-touching transitions faster than a branch can finish a
CI cycle. That is not an argument against the rule -- the ledger stands at 2 rows instead of 62
precisely because it is paid on touch -- but it does mean the toll scales with how long a branch
stays open, and the honest way to shrink it is shorter branches, not deferred payment.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ

---------

Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: gunbai-bot[bot] <289086189+gunbai-bot[bot]@users.noreply.github.com>
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