Skip to content

Enroll both instance-gap carriers in cited-symbol resolution, with a counted outside-index disposition - #8775

Merged
briansrls merged 5 commits into
mainfrom
session/wise-boar-649-citation-enrollment
Aug 21, 2026
Merged

briansrls merged 5 commits into
mainfrom
session/wise-boar-649-citation-enrollment

Conversation

@briansrls

@briansrls briansrls commented Aug 21, 2026 •

Copy link
Copy Markdown
Contributor

What this is

The widening v2.lens.cited_symbol_resolution's own law names as its next step: enrollment widens to every structural DeclarationRef carrier. Both instance-gap carriers project their refs into that lens's production population, resolved by v2.std.decl_ref_resolution unchanged — no second resolver, no new authority.

Landed under an operator ruling ((e), after (a)–(d) were each rejected — see Why not simply exclude below).

The enrollment caught a defect on its first execution, in a merged carrier

Two of gunbc.list_membership_operation_gap's five rows (merged as #8735) cited the filename — test.claim.attribution_span_witness_test — where the module declares itself without the _test suffix.

That carrier passed four reviews, one of which verified its citations by hand. A name-level grep passes on both rows because the declaration names were correct and only the address was wrong. Hand-verification and grep both certify a citation that resolution rejects.

The spelling fix was necessary and insufficient

Per-ref probe, one process per ref, with positive controls:

ref verdict
v2.compiler.parse.parse_lexeme_digest PASS
v2.std.compilers.target_model.target_value_expr_effect_apply_callee PASS
v2.compiler.tokenize.lex_match_prefix PASS
gunbc.publication_policy.known_publication_roots PASS
gunbc.session_auto_publish.write_set_refusals PASS
extdeps.unicode.blocks.zero_width_codepoints PASS
test.claim.attribution_span_witness.unattributed_widths FAIL
test.claim.recorded_observation_envelope_witness.active_ids FAIL

Root cause, established with controls so a FAIL means more than an unsatisfied predicate: the modules are in module_declaration_facts_live (control: gunbc.publication_policy likewise), and there is no decl_facts row from those files at all (control: dag/gunbc/publication_policy.dag rows are present). v2.std.decl_index decl_facts skips test .dag files deliberately — gunbc.ci_layer_roots records the exclusion in the row explaining why a second walk must not skip them.

Those two citations are true and unanswerable at once: DESIGN §4b's outside-the-modeled-guarantee column.

The shape

std.decl_ref gains, beside DeclarationRef because it is a fact about references generally:

type CitationIndexCoverage
  = CitableThroughDeclIndex
  | OutsideDeclIndexTestWitnessModule

One axis, N variants — not a wrapper around a nested class enum. A single-variant coproduct is read as a type alias and does not export its variant name; measured, not assumed.

Both carriers carry index_coverage per row and project three things: citable refs (what enrolls), outside-index refs, and a count. Never a silent subtraction.

The lambda carrier's rows are all citable today and it carries the filter anyway — a carrier that grows the filter only when it first needs one has a green that silently changes meaning that day.

Why not simply exclude the two rows

Because that green would mean "nothing left to check". This one means "N resolved, M outside the index, here is which and why". The difference is whether the number stays readable, and it is the operator's stated condition: an uncounted disposition degrades into an exemption list.

The guard that enforces it — instance_gap_outside_index_refs_really_do_refuse — asserts the refs marked outside-index actually refuse, in exactly the claimed count. A partition witness holds citable + outside == total.

Verification

Six witnesses PASS. The guard is mutation-tested, not asserted: swap a resolvable row to outside-index and a genuinely-outside row to citable — chosen because it leaves the count at 2, so the counting witness cannot see it.

MUTATED ..._population_is_counted        :: PASS   <- blind to the swap, by design
MUTATED ..._outside_index_refs_really_do_refuse :: FAIL
MUTATED ..._declaration_refs_all_resolve :: FAIL

So marking a resolvable ref outside-index to dodge a red cannot pass, and the counting witness is measured insufficient alone rather than assumed to be. Mutated file restored byte-identical before commit.

Known-red, pre-existing, not from this change

cited_symbol_resolution_lens_is_green_on_live_corpus fails on unmodified main — established by stashing all four files and re-running clean. It is 27 violations on main, of which 4 are this same outside-index class; quiet-lark-881 owns that lane and will consume this shape rather than mint a second one. All 16 witnesses in that file are OfflineLocalRecipe, so nothing runs them in CI today — which is why the lens could sit red unnoticed.

— sent from wise-boar-649

Brian Searls and others added 3 commits August 21, 2026 12:02
…e, as a carrier

Three E0282 sites in the emission boundary share one mechanism: v1's
emit_rust emit_typed_call binds a lambda argument's parameter types only
when the callee's SPELLED name is one of four literals (map, filter,
flat_map, fold). A callee that resolves to a real declaration taking a
function parameter, but is spelled anything else, gets its lambda emitted
with no parameter annotation and rustc has nothing to infer from.

The three sites are the discriminating RED for the root lane: two are
near-misses of a roster name (fold_list vs fold) and one is absent from
the roster entirely (is_prefix_of), so a fifth literal key closes two of
three and the class survives — which is the point. `callee` is already in
scope at the gate, resolved, five lines below.

Population is carried as an UPPER BOUND (UpperBoundPendingResidueCheck),
not a measurement: the residue half of the E0282 partition is weaker than
the converted half, and the standing prediction is that the true count is
higher.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…counted outside-index disposition

Widening, not a new authority: the two instance-gap carriers project their
DeclarationRefs into v2.lens.cited_symbol_resolution's production population,
resolved by v2.std.decl_ref_resolution unchanged. This is the widening that
lens's own law names as its next step.

THE ENROLLMENT CAUGHT A DEFECT ON ITS FIRST EXECUTION, in a MERGED carrier.
Two of gunbc.list_membership_operation_gap's five rows (#8735) cited the
FILENAME — test.claim.attribution_span_witness_test — where the module
declares itself without the _test suffix. Four reviews passed over those rows,
one of which verified the citations by hand; a name-level grep passes because
the declaration names were right and only the address was wrong.

THE SPELLING FIX WAS NECESSARY AND INSUFFICIENT. Per-ref probe with positive
controls: 6 of 8 refs resolve; the two test.claim rows still refuse because
v2.std.decl_index decl_facts SKIPS TEST .dag FILES DELIBERATELY. Their modules
are in module_declaration_facts_live; their declarations are in no decl_facts
row at all. Those citations are true and unanswerable at once — DESIGN 4b's
outside-the-modeled-guarantee column.

So std.decl_ref gains CitationIndexCoverage (one axis, two variants; a
single-variant coproduct is read as a type alias and does not export its
name), both carriers carry it per row, and each projects citable refs,
outside-index refs, and a COUNT — never a silent subtraction.

Six witnesses, and the honesty guard is mutation-tested rather than asserted:
swapping a resolvable row to outside-index and an outside row to citable keeps
the count at 2, so the counting witness stays green and both honesty witnesses
go red. Marking a resolvable ref outside-index to dodge a red cannot pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…-citation-enrollment

# Conflicts:
#	dag/gunbc/lambda_argument_typing_gate.dag
@gunbai-bot gunbai-bot Bot changed the title self host others Enroll both instance-gap carriers in cited-symbol resolution, with a counted outside-index disposition Aug 21, 2026
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 21, 2026 16:06
@gunbai-bot

gunbai-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Rung correction on this PR's own evidence, before it merges

The body says the honesty guard is mutation-tested, and it is. It does not say clearly enough where that guard runs, and the answer changes its rung.

All four new witnesses land in dag/test/claim/long/cited_symbol_resolution_witness_test.dag, which gunbc.ci_layer_roots classifies as OfflineLocalRecipe — the same non-execution I noted for the incumbent 16 and did not apply to my own additions in the same breath. So as merged, this PR's guard is:

  • mutation-tested — the swap turns it red, measured, not asserted;
  • not executing in CI — it runs when someone runs the local recipe, which is exactly the defect quiet-lark-881's lane exists to fix.

That makes the honest rung mitigatable today, not mechanically preventable. A guard that discriminates but never runs is evidence, not enforcement, and calling it enforcement here would be the rung inflation DESIGN §4b names as worse than sitting low.

Next-rung trigger, already in flight: quiet-lark-881 is putting the same two checks in the executing path rather than in a witness — claim_executor --required-ci refuses if a ref marked outside-index actually resolves, and refuses on a count disagreement (measured 2m09s wall for the whole census including resolve). When that phase lands, this class reaches mechanically preventable on every CI run, and these witnesses stay enrolled as the discriminating evidence that the higher rung is real — §4b(4): the climb deletes redundant production handling, never the evidence.

I am deliberately not duplicating their guard here. Two implementations of one check is the fork §3 forbids, and the one in the executing phase is the one that counts.

Also settled since this PR opened, by quiet-lark-881 running the probe with the positive control: the fourth suspected victim (v2.test.round_trip.dag_comment_wall_test, under src/v2/test) is not a second cause. The src/v2 root is indexed — the control proves the walk reaches it — and the file is skipped for being a test file, same as the three under dag/test/claim. All four refuse through the same DECLARATION-ABSENT arm. OutsideDeclIndexTestWitnessModule covers all four; no second variant is needed, which was the open question I flagged when handing them the shape.

— sent from wise-boar-649

Brian Searls and others added 2 commits August 21, 2026 16:53
… type drifted

dag/std/decl_ref.dag is in the v1 seed closure, so adding the coproduct
drifted its stage0 mirror. CI reported it twice from one cause:

  required-ci: regen FAIL generated surface drift: std_decl_ref.rs
  behavioral-receipt: std.decl_ref REFUSED — seed: the driver did not compile
    against the mirror: could not find `CitationIndexCoverage` in
    `std_decl_ref`; cannot find function `citation_is_outside_index`

Emitted by claim_executor --required-regen and installed from the candidate
tree, that ONE file only — the candidate also carries a Cargo.toml and omits
bin/, so a whole-tree copy-back would contaminate hand-maintained files.

Regen's drift set was exactly one file, so no other mirror is implicated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@briansrls
briansrls merged commit e336acc into main Aug 21, 2026
1 check passed
@briansrls
briansrls deleted the session/wise-boar-649-citation-enrollment branch August 21, 2026 18:51
gunbai-bot Bot pushed a commit that referenced this pull request Aug 21, 2026
…use, not a copied one

Adding per-site `cause` and `cause_receipt` to LambdaTypingGateSite made every
existing literal incomplete, and the floor refused exactly one:
dag/test/claim/long/cited_symbol_resolution_witness_test.dag's planted red
control, landed by #8775 after this branch's type change was authored. That
refusal is the fail-closed census working -- the widened type surfaced its one
real dependent loudly rather than silently defaulting it.

The planted site is SYNTHETIC: it names a declaration that does not exist, so no
probe can have measured why it fails to type and there is nothing for a receipt
to point at. It therefore carries SiteCauseUnmeasured / NotYetProbed, and an
annotation says why it must stay that way -- copying a real site's cause here to
make the literal look complete would put a measured attribution on a specimen no
run produced, which is the fabricated-receipt failure the receipt field exists to
prevent.

Census over the corpus: this is the only LambdaTypingGateSite literal outside the
carrier itself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Aug 21, 2026
…lta, so #8758's carrier gets a corrected cause (two roots, per-site) and the four-name roster goes as cleanup (#8772)

* wip: lambda_argument_scope (roster removal + per-arg lambda scope)

* Correct #8758's carrier: the mechanism it names is refuted, the sites and the derivation stand

The row asserted a cause -- emit_typed_call's four-name collection_scope gate
produces the three E0282 sites. Two-arm emission over three closures, from two
binaries whose difference was confirmed before either arm ran, is byte-identical:
258 files per arm, 0 differing files, 0 differing lines. A third arm deleting the
binding entirely is also identical, which is what separates "refuted" from "my
replacement happens to agree with the roster".

The mechanism cannot reach emitted bytes: scope.locals has exactly one reader in
the Rust emitter (is_already_optional) on the arm taken only when a node carries
no resolved type, and the declared parameter types the gate was meant to supply
are already bound onto the lambda's param nodes one stage earlier by infer_expr's
ExprCall/ExprLambda path.

THE DISSOLUTION TRIGGER WAS THE DANGEROUS HALF. It keyed on repairing that gate,
so it was exactly satisfiable by a change that fixes nothing -- delete the roster,
retire the row, three sites still red. A false cause misleads a reader; a false
trigger disposes of the evidence. The replacement keys on the three sites emitting
and compiling without an inference failure, and says outright that no repair to
the gate satisfies it.

Not over-retracted: the three sites, the E0282 x E0061 intersection that derived
them, and UpperBoundPendingResidueCheck with its standing prediction all survive
untouched -- none depended on the cause. The surface is still a bare-name-keying
shape, now at the honest strength: syntactic, with no observable consequence.

The reach figure is deleted rather than softened; it sized the blast radius of
repairing a mechanism that changes no byte.

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

* Per-site cause on the lambda-typing-gate row, and finish #8597's map_keys conversion

CARRIER: cause becomes a PER-SITE field, because the sites and the causes were
established by different instruments with different groupings. The three sites
were derived together by one intersection over one subject; the causes were
established one site at a time by three cargo probes over three emitted
closures. A single row-level CauseAttributed would force one instrument's
grouping onto the other's -- the same collapse this row was already corrected
for once.

  parse/parse_lexeme_digest        StringDeclarationSiteAlias   (help annotates ch)
  target_model/...apply_callee     UntypedFoldInitAccumulator   (help annotates acc)
  tokenize/lex_match_prefix        StringDeclarationSiteAlias   (help annotates a)

Three real reds, TWO causes. Row-level CauseUnlocated is retired rather than
answered, replaced by CauseGrouping = CausePerSite. The dissolution trigger now
states that no single repair can fire it.

The discriminator is free and sits in output everyone reads past: rustc's help
names WHICH parameter it wants annotated. Element means the collection could not
supply T; accumulator means the fold's init could not supply its own type.

Also recorded: a pre-registered hunch that was REFUTED (field access on the
lambda parameter was named in advance as the first place to look, and rustc's
caret is on acc, never on row), and a warning that four E0282s in the parse
crate belong to the held contains class so a count there is not a population.

MAP_KEYS, NOT MINE AND SAID SO: the witness floor refuses on
trait_derive_supplemental_generic_bound_contract_test.dag with "method 'keys'
not found on receiver type 'Map(...)'". Confirmed pre-existing on main at
c603c06 -- same file, same two lines, same message, on a commit unrelated to
this branch. #8597 converted six sites in that file to map_keys and left two
behind. This applies the same conversion to the stragglers; it repairs a
main-wide red, not a defect this branch introduced.

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

* Retract 'closes a real leak' in the emitter comment: the same null refutes it

The per-argument narrowing was described as closing a real leak -- one lambda's
parameter names visible while emitting sibling arguments and filled defaults.
That is a mechanism claim, and the measurement in this PR refutes it exactly as
it refutes the roster: scope.locals is read once in the whole Rust emitter, on
an arm taken only when a node carries no resolved type, so nothing measured
shows the leak producing a wrong byte.

It is now stated as construction cleanup with no measured current consequence --
narrowed because the narrow form is the correct construction, not because a
defect was observed, and unearned as a repair until a fixture makes it
observable.

A change whose whole point is that an unmeasured mechanism claim was wrong must
not carry a second unmeasured mechanism claim in its own text. Same defect, one
level down. Caught by external review, not by me.

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

* Correct the map_keys attribution: the two .keys() lines are #8749's, not #8597's

Commit bbf4350 in this branch blamed #8597 for the two surviving `.keys()`
call sites. That is wrong, and a commit repairing a main-wide red while
misattributing it puts a false fact in the durable record beside a true fix.

Verified per-commit on the file rather than taken on trust:

  #8726  dd1ac18   +6 map_keys lines,  +0 .keys() lines
  #8749  8077603   +0 map_keys lines,  +2 .keys() lines   <- introduced both
  #8597  aa8a65e   +0 in either direction, touched neither

THE MECHANISM IS ALSO NOT WHAT bbf4350 SAID. It described an incomplete
conversion -- six done, two missed. It was not. #8726's sweep was COMPLETE when
it ran: it converted every site that existed at that point. #8749 then
introduced NEW uses of the retired spelling, from a branch that predated the
deletion. No census over #8726's tree could have found them, because they did
not exist yet.

So the class is REINTRODUCTION AFTER A SWEEP, not a missed census, and it is a
merge-time question rather than a branch-time one: neither branch is wrong on
its own, and the defect exists only in their union. Nothing guards that today.

This two-line repair is therefore the right SCOPE and explicitly NOT the root.
It clears a main-wide red; what stops the next reintroduction is unbuilt.

Caught by quick-lynx-620 pushing back on the attribution I was given.

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

* File the second cause as its own row: untyped fold-init accumulator

The target_model site in lambda_typing_gate_sites has a distinct cause with a
distinct repair, so it gets a row. empty_map() in a fold's `empty:` position
emits as v1_rt::rc_empty_map::<_, _>(); the only thing that could close those
type parameters is the fold's own closure, which RECEIVES the accumulator -- so
the target compiler is asked to infer a parameter's type from a body that uses
it, and refuses.

What rules out the neighbours, since this site was first filed under one: the
collection is a genuine List<TargetEffectCalleeRow>, rustc never asks about
`row`, and `acc` traces to the init rather than to the collection or the
callee's spelling. The discriminator is rustc's own help text naming which
parameter it wants annotated -- |acc: Type, row| here, |acc, ch: Type| for the
collection-realization class.

POPULATION IS ObservedSitesOnly. One measured site is not a census: this one was
found only because it sat in a partition being probed member by member, and no
sweep for untyped empty-collection literals in fold-init position has been run.
The sweep is named rather than performed so the absence is a stated gap, not an
implied zero.

The site STAYS LISTED in lambda_typing_gate_sites with a cross-reference, because
that row records that the three were derived TOGETHER by one intersection over
one subject. Removing a member because its cause turned out to differ would
destroy the only artifact of that derivation.

Trigger is keyed to the site compiling, not to any repair -- the sibling row
learned that the expensive way. It also refuses the cheap escape: annotating the
closure at the call site moves the obligation to the author instead of deriving
it.

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

* The census refused a synthetic control literal: give it the honest cause, not a copied one

Adding per-site `cause` and `cause_receipt` to LambdaTypingGateSite made every
existing literal incomplete, and the floor refused exactly one:
dag/test/claim/long/cited_symbol_resolution_witness_test.dag's planted red
control, landed by #8775 after this branch's type change was authored. That
refusal is the fail-closed census working -- the widened type surfaced its one
real dependent loudly rather than silently defaulting it.

The planted site is SYNTHETIC: it names a declaration that does not exist, so no
probe can have measured why it fails to type and there is nothing for a receipt
to point at. It therefore carries SiteCauseUnmeasured / NotYetProbed, and an
annotation says why it must stay that way -- copying a real site's cause here to
make the literal look complete would put a measured attribution on a specimen no
run produced, which is the fabricated-receipt failure the receipt field exists to
prevent.

Census over the corpus: this is the only LambdaTypingGateSite literal outside the
carrier itself.

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

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 26, 2026
…enty-seven witnesses that were never its

DESIGN authorised this cut and got its population wrong, which is the finding rather than
a footnote. The row read "v2.lens.cited_symbol_resolution and its sixteen witnesses are not
deleted -- they are unreachable from any required check and are dead rather than competing".
Both halves of that population claim are false, and this change corrects the row in the same
diff that falsifies it.

SIXTEEN WAS THE COUNT AT #7707, when the lens landed. The file grew twice after
(#8673 enrolled roster_registry, #8775 the two instance-gap carriers) and held 27 `test fn`
identities. `gunbc.ci_layer_roots` said "eighteen". Three numbers, three snapshots of a
growing file, none of them current -- the transcribed-measurement class the standing rule
already names. The replacement rows name their subject and no number.

AND "DEAD" WAS TRUE OF THE LENS AND FALSE OF A THIRD OF ITS WITNESSES. Measured against the
seven symbols that file imported FROM the lens, 6 of the 27 touch one. The other 21 do not.
"The lens and its witnesses" was never one population, and the three-way split is:

  6  LENS-BOUND -- die with it. The census-green claim, the three planted-control rows, the
     enrolled-population exemption identity, the ambiguous control. `declaration_index`
     re-derives this machinery as PLANTED_CONTROL_CITATIONS plus PlantedControlNoLongerRefuses.

  6  RESOLVER-BOUND -- MOVED, not deleted, to test.claim.long.decl_ref_resolution_witness_test.
     They call `resolve_declaration_ref`, which lives in `v2.std.decl_ref_resolution` -- a
     module that SURVIVES with four other consumers -- and they are the only rows in the tree
     that execute its five-arm refusal. Deleting them because they sat in a file named for
     the lens would be the §4b(4) failure exactly: a climb deletes the redundant PRODUCTION
     machinery, never the discriminating RED and positive control.

  15 CARRIER-BOUND -- MOVED to test.claim.long.carrier_reference_integrity_witness_test.
     Population and projection claims about the four carriers that PROJECT DeclarationRefs.
     Their resolution half is subsumed; their population half is subsumed by nothing.

SUBSUMPTION IS SCOPED, not general: `declaration_index` extracts TYPED-LITERAL citations --
DeclarationRef record literals and the decl_ref/decl_field_ref constructors -- and reports
computed reference fields as a coverage boundary. A prose reference inside a String is
covered by nothing, before or after, and this change does not claim otherwise.

THE PER-PR WITNESS IS RENAMED, NOT DELETED. test.claim.cited_symbol_resolution_witness_test
never imported the lens; its one claim is a three-term bucket partition over
gunbc.doc_graph_roots. Two readers independently concluded from its NAME that the resolution
law was enforced per-PR -- it was not, a bucket identity was -- and after this cut it would
have been the only cited-symbol-named thing left in the tree, reading as the law's residue.
It is now test.claim.doc_graph_reference_partition_witness_test. Same borrowed-authority
shape as #9252's fixture rehome, one layer up: there the home was borrowed, here the name.

WHAT THE WALL ITSELF NAMED, because this was cut delete-first and the census is the deletion.
The first corpus run after the cut reported six refusals: two IMPORT-MEMBER-ABSENT for a
`CitedSymbolResolution` lens-id the registry no longer declares, and four
PLANTED-CONTROL-RESOLVES for the exact rows #9211 declared as this cut's residue ("they
delete with the lens, not before it"). Every one predicted, none discovered by reading.

AND ONE GAP THE ROSTER DELETION WOULD HAVE OPENED, which is why those four rows are not
simply removed. Each named one refusal arm of the cited-symbol wall. Three of the four arms
already had controlled fixtures in tests/declaration_index_integrity.rs. THE FOURTH DID NOT:
measured, the string `CitedFieldAbsent` did not occur in that file at all, so its only
evidence anywhere was the planted row I was deleting. Deleting it would have left a refusal
arm with nothing executing against it -- §4b(4) again, one level up from where I first hit it.
`citation_to_an_absent_field_is_refused_and_a_present_field_is_not` is authored here, with
its positive control, and a controlled fixture is the stronger oracle anyway (§5): the
planted row only ever asserted that one hand-authored citation still refuses.

PLANTED_CONTROL_CITATIONS is left EMPTY rather than deleted. Mechanism reachable, join
reachable, occupancy zero -- a healthy guard being quiet, not a dead one.

EVIDENCE, by execution (remote, release binaries):
                              before        after
  parse-clean files           4012          4011      the lens module
  modules                     4012          4011
  citations                   1470          1466      the lens's four planted citations
  lens_modules                71            70
  debt                        42            42        UNCHANGED
  corpus findings             0             0
  declaration_index_integrity 21 passed     22 passed the new field-absent pair

THE DEBT COUNTS RECONCILE, and the brief's "46" is none of them. 38 = roster rows, counted.
46 = citation SITES at the time the roster's doc comment was written. 42 = citations
currently suppressed by a row, the live measurement. debt is 42 before and after, and a row
that stopped reproducing refuses as CitationDebtRowStale -- none did, which is the executable
form of "the defects are still found".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Aug 26, 2026
…ction, cli_invoke builders, walk_plan_stage fixture family) (#9286)

* Delete the .dag residue of the plan/walk CLI surface, and give the scope-disposition witness a fixture home it owns

#9228 deleted claim_executor's plan/walk surface and named its .dag residue rather
than sweeping it. This is that cut, plus one repair the census surfaced.

WHAT WENT, AT THE ROOT:

  PlanFunction and the plan argv builders. The coproduct modelled a closed roster of
  --plan-function targets; the flag no longer parses and the entry every variant named
  (src/v2/workflow/ci_floor_plan.dag) was deleted by the 2026-08-15 floor cut. Gone with
  it: claim_executor_run_plan_transport_argv, claim_executor_run_plan_shell, the
  notice-title normalizer and shell suffix that existed only to feed them,
  claim_executor.Executor.RunPlan, ci_spec's scheduler_invoke/scheduler_invoke_with/
  floor_plan_entry/floor_plan_function/plan_artifact_plan_function, and
  gunbc_ci_floor_only_script.

  The --verify-build-artifacts half is UNTOUCHED and deliberately so: it is a live mode
  (fleet-converge.yml), so claim_executor_verify_artifacts_shell, claim_executor_bin_shell,
  release_bin_shell_path and SourceRootShellStyle all stay. cli_invoke's dissolve trigger is
  NARROWED to name only what survives rather than deleted, since the shell-vs-argv fork it
  records is still open for that one spelling.

  gunbc_ci_run_script emitted the release build AND a claim_executor --plan-entry line. The
  second half is deleted, not repointed at --required-ci: witnesses.yml already invokes that,
  and a second route to it here is the parallel authority the floor cut removed.

  The walk_plan_stage fixture family, whole: 11 fixture modules, the 379-line #[ignore]
  harness, its scaffold row and witness, and the seed_retention_frontier retained_test_harness
  row. Their sole driver was the plan.dag recipes #9228 deleted.

  v2.workflow.required_floor fixture_home_prefixes() and RequiredFloorDisposition::
  DeclinedFixtureMember, with the cli_run.rs decode, branch, counter and TSV column. That
  arm's roster was one prefix and the family above was its entire population; its own header
  said "DISSOLVES when the fixture stops authoring test fns", and this is that condition.
  Coordinated with sleek-carp-211, who is modelling the enum in #9246 and asked for both
  sides deleted here.

  The pre-push witness-corpus gate. Not on the brief, found by the flag census:
  pre_push.rs built claim_executor and invoked --plan-entry/--plan-function on the deleted
  floor plan entry. Its EMISSION died 2026-07-25 when the operator made the hook fmt-only;
  its INVOCATION died 2026-08-25 with the flags. Two witness rows asserting "a .dag push arms
  a gate" are deleted rather than weakened -- measured against the roster, the corpus binding
  was the only thing making them true, so they were green against the plan and false about the
  hook anyone runs.

THE REPAIR THE CENSUS SURFACED (tools.dag_compile_clean_scope):

  Three walk_plan_stage files were pinned as the roster and pool of the SCOPE DISPOSITION
  witness, which has nothing to do with plan/walk. Its own note records that these same
  specimens already moved once for exactly this reason -- from test/fixture/floor_skip, which
  died with affected-set selection. This would have been the third home.

  They are rehomed to src/v2/test/fixture/compile_clean_scope/, a home this witness owns:
  three modules, no test fn, no effects, one consumer. No discovery exclusion is needed
  because there is nothing to discover, which is a stronger construction than the dir-grain
  exclusion the old home required.

  AND THE PROPERTY THE NOTE CLAIMED IS NOW ASSERTED. The expectation was
  ExpectScopedContaining -- MEMBERSHIP -- so a selector returning the whole roster satisfied
  every row and the "strict-subset proof" the note describes was checked by nothing.
  ExpectScopedExactly compares the selected list to the expected list.

EVIDENCE, by execution on a release gunbc (remote, one dispatch):
  control    witness_touched_path_dispositions_hold -> true
  mutation   give scope_isolated an import edge to scope_shared -> false
  The mutation is exactly the strict-subset violation; the old assertion could not see it.

Rust: cargo check -p v1-compiler --bins clean, fmt clean.

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

* Repair the scope-disposition witness's per-PR half, which the floor caught

dag/test/claim/dag_compile_clean_scope_witness_test.dag imports ExpectScopedContaining
and pins the disposition row count. Both moved with the rehoming and I checked only the
long-lane witness, so strict preparation refused with a name-resolution error before any
site ran. Fixed at both ends: the import drops the deleted variant (ExpectSkip went with
it -- it was imported and never used), and the pin goes 7 -> 8, which is the roster
growing by one row because the strict-subset proof needs three specimens where the old
home carried two.

The pin doing its job here is the argument for keeping it: a count that had to be updated
by hand is exactly what stopped this rehoming from silently shipping a roster of a
different size than the one the note describes.

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

* Delete the `gunbc ci` verb rather than leave a command named ci that greens without running CI

REQUEST_CHANGES from codex/gpt-5.6-sol (review 56054), and the finding is correct.

WHAT I BROKE. This branch narrowed gunbc_ci_run_script to ci_release_build_script()
alone, because its other half emitted a `claim_executor --plan-entry` line naming an
entry the floor cut deleted. But `gunbc ci` is a real CLI subcommand, so what survived
was a callable verb that builds the release binaries, verifies the artifacts, and exits
0 -- under a name that says it ran CI. That is fail-open semantic dilution: the failure
mode is not a wrong answer, it is a CORRECT answer to a much smaller question, reported
under the name of the larger one. §5's absorbing-fallback rule is about a failure arm
that widens; this is its mirror at the success arm, a green that narrowed.

WHY DELETED AND NOT REBOUND. Binding the verb to `claim_executor --required-ci` was the
reviewer's other option and I am not taking it, on the grounds this branch already
argued in the commit that caused the defect: witnesses.yml invokes --required-ci, and a
second route to it is the parallel authority the floor cut removed. The verb also has no
distinct job left -- "build the release binaries and verify the artifacts" already has a
name, ci_release_build_script, and fleet-converge.yml already calls it. So the verb is
not an authority that lost its body; it is a name with nothing left to denote.

THE CENSUS, cut at the root and followed where it led:
  dag/tools/gunbc_ci.dag                     the entry module, deleted
  main.rs Commands::Ci + its arm             the CLI verb
  gunbc.cli_dispatch_surface "ci" row        the modeled CLI surface
  gunbc_cli_dispatch_surface.rs              its generated mirror
  v2.workflow.ci_release_build_emit          gunbc_ci_run_script, the wrapper
  std.emit_on_demand gunbc_ci_emission_surface   the wet-surface row naming tools.gunbc_ci main
  emit_on_demand_kernel_witness_test         its enrollment assertion
  wall_residue_live_test residue_gunbc_ci_clean  a test fn whose subject was the deleted file

ci_release_build_script itself is UNTOUCHED and still has three consumers
(ci_materialization, fleet_workflow_steps, fleet-converge.yml). Only the wrapper goes.

EVIDENCE, build lane on this tree (remote, one dispatch):
  required-ci: lane=build phases_run=2 failed=0
  regen first_generation_equal=true    -- the mirror edit is byte-equal to the emitter's
                                          own output, established by the gate rather than
                                          by my reading of the diff
  v2-emission blocking=0, census 3792 -> 3791, the one deleted module

The emitter-gap witness still holds: gap_is_non_empty_while_the_divergence_row_stands
needs at least one AbsentFromEmitMainRs row and 17 remain after this one goes.

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

* Delete v2.lens.cited_symbol_resolution, and keep the twelve of its twenty-seven witnesses that were never its

DESIGN authorised this cut and got its population wrong, which is the finding rather than
a footnote. The row read "v2.lens.cited_symbol_resolution and its sixteen witnesses are not
deleted -- they are unreachable from any required check and are dead rather than competing".
Both halves of that population claim are false, and this change corrects the row in the same
diff that falsifies it.

SIXTEEN WAS THE COUNT AT #7707, when the lens landed. The file grew twice after
(#8673 enrolled roster_registry, #8775 the two instance-gap carriers) and held 27 `test fn`
identities. `gunbc.ci_layer_roots` said "eighteen". Three numbers, three snapshots of a
growing file, none of them current -- the transcribed-measurement class the standing rule
already names. The replacement rows name their subject and no number.

AND "DEAD" WAS TRUE OF THE LENS AND FALSE OF A THIRD OF ITS WITNESSES. Measured against the
seven symbols that file imported FROM the lens, 6 of the 27 touch one. The other 21 do not.
"The lens and its witnesses" was never one population, and the three-way split is:

  6  LENS-BOUND -- die with it. The census-green claim, the three planted-control rows, the
     enrolled-population exemption identity, the ambiguous control. `declaration_index`
     re-derives this machinery as PLANTED_CONTROL_CITATIONS plus PlantedControlNoLongerRefuses.

  6  RESOLVER-BOUND -- MOVED, not deleted, to test.claim.long.decl_ref_resolution_witness_test.
     They call `resolve_declaration_ref`, which lives in `v2.std.decl_ref_resolution` -- a
     module that SURVIVES with four other consumers -- and they are the only rows in the tree
     that execute its five-arm refusal. Deleting them because they sat in a file named for
     the lens would be the §4b(4) failure exactly: a climb deletes the redundant PRODUCTION
     machinery, never the discriminating RED and positive control.

  15 CARRIER-BOUND -- MOVED to test.claim.long.carrier_reference_integrity_witness_test.
     Population and projection claims about the four carriers that PROJECT DeclarationRefs.
     Their resolution half is subsumed; their population half is subsumed by nothing.

SUBSUMPTION IS SCOPED, not general: `declaration_index` extracts TYPED-LITERAL citations --
DeclarationRef record literals and the decl_ref/decl_field_ref constructors -- and reports
computed reference fields as a coverage boundary. A prose reference inside a String is
covered by nothing, before or after, and this change does not claim otherwise.

THE PER-PR WITNESS IS RENAMED, NOT DELETED. test.claim.cited_symbol_resolution_witness_test
never imported the lens; its one claim is a three-term bucket partition over
gunbc.doc_graph_roots. Two readers independently concluded from its NAME that the resolution
law was enforced per-PR -- it was not, a bucket identity was -- and after this cut it would
have been the only cited-symbol-named thing left in the tree, reading as the law's residue.
It is now test.claim.doc_graph_reference_partition_witness_test. Same borrowed-authority
shape as #9252's fixture rehome, one layer up: there the home was borrowed, here the name.

WHAT THE WALL ITSELF NAMED, because this was cut delete-first and the census is the deletion.
The first corpus run after the cut reported six refusals: two IMPORT-MEMBER-ABSENT for a
`CitedSymbolResolution` lens-id the registry no longer declares, and four
PLANTED-CONTROL-RESOLVES for the exact rows #9211 declared as this cut's residue ("they
delete with the lens, not before it"). Every one predicted, none discovered by reading.

AND ONE GAP THE ROSTER DELETION WOULD HAVE OPENED, which is why those four rows are not
simply removed. Each named one refusal arm of the cited-symbol wall. Three of the four arms
already had controlled fixtures in tests/declaration_index_integrity.rs. THE FOURTH DID NOT:
measured, the string `CitedFieldAbsent` did not occur in that file at all, so its only
evidence anywhere was the planted row I was deleting. Deleting it would have left a refusal
arm with nothing executing against it -- §4b(4) again, one level up from where I first hit it.
`citation_to_an_absent_field_is_refused_and_a_present_field_is_not` is authored here, with
its positive control, and a controlled fixture is the stronger oracle anyway (§5): the
planted row only ever asserted that one hand-authored citation still refuses.

PLANTED_CONTROL_CITATIONS is left EMPTY rather than deleted. Mechanism reachable, join
reachable, occupancy zero -- a healthy guard being quiet, not a dead one.

EVIDENCE, by execution (remote, release binaries):
                              before        after
  parse-clean files           4012          4011      the lens module
  modules                     4012          4011
  citations                   1470          1466      the lens's four planted citations
  lens_modules                71            70
  debt                        42            42        UNCHANGED
  corpus findings             0             0
  declaration_index_integrity 21 passed     22 passed the new field-absent pair

THE DEBT COUNTS RECONCILE, and the brief's "46" is none of them. 38 = roster rows, counted.
46 = citation SITES at the time the roster's doc comment was written. 42 = citations
currently suppressed by a row, the live measurement. debt is 42 before and after, and a row
that stopped reproducing refuses as CitationDebtRowStale -- none did, which is the executable
form of "the defects are still found".

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

---------

Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brian Searls <11205878+briansrls@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