Skip to content

Partition the floor's 164 runtime-errored identities, and land the compiler control the specimens were the only evidence for - #9022

Merged
briansrls merged 1 commit into
mainfrom
session/neat-deer-718
Aug 23, 2026
Merged

briansrls merged 1 commit into
mainfrom
session/neat-deer-718

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Required-floor run 32633501354 (main, head 907f19c) reports
known_red_runtime_errored=164: programs the compiler ACCEPTED and the
interpreter could not evaluate. That counter is the class's only observer and
it falls to zero as the witnesses are repaired — gunbc#9006 is repairing 21 of
them right now — so the evidence had to stop living in the specimens.

The partition, its producer, and the per-identity rows are
docs/plans/receipts/floor-runtime-error-partition-2026-08-23/. Five causal
families; the reference-unavailable subset is 149 of the 164 and every one of
its names IS declared somewhere in the corpus — the undeclared-anywhere class
is EMPTY, so intended compile state never separates on the name not existing.
It separates on where the declaration lives: 126 identities reference a
module-scope data in an unimported module, 9 a bare variant or type name, 8
a fn, 5 a test data in another test file, 1 a type in call position.

WHAT LANDS AS A FIXTURE: HOST-PRIMITIVE-CONTRACT, 11 of the 164. Measured on
compile_dag_rust_emit_check at this head, a host primitive's argument list is
unchecked at compile in every direction — two arguments, zero arguments, and
one argument of the wrong type all compile clean, and the host arm then refuses
each at evaluation with requires exactly one string argument. Three REDs
assert the refusal belongs at compile; three positive controls (clean compiles,
broken refuses, the CORRECT one-string call still compiles) make each RED
discriminating rather than a blanket claim. All six measured by execution:
controls true, REDs false. The three are enrolled in floor_expected_red so the
day the contract is checked they PASS and red the build naming themselves.

WHAT DOES NOT LAND, as a measurement rather than an omission: no fixture for
the 149. Both .dag-callable compile-observation surfaces REFUSE that shape
(compile_dag_rust_emit_check false, compile_diagnostic_census blocking) while
the floor's own witness loader ACCEPTS it, because that loader runs
extend_with_bare_reference_closure and resolves the name through the tree
census. A fixture on either surface would be permanently green and cited as
coverage of a class it never touches. Its next-rung trigger is a
compile-observation surface resolving names by the witness loader's rule.

Discriminating control for that claim, executed both ways: a source calling
argument_form_is_valid(design_argument) with no imports compiles silent and
throws NoSuchFunction at evaluation; the identical source with
import gunbc.design_argument { design_argument } compiles and evaluates true.
The import is the whole discriminator and the compiler says nothing about it.

Enrolment verified by execution: roster length 203, the identity present once.

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

🤖 Generated with Claude Code

…mpiler control the specimens were the only evidence for

Required-floor run 32633501354 (main, head 907f19c) reports
known_red_runtime_errored=164: programs the compiler ACCEPTED and the
interpreter could not evaluate. That counter is the class's only observer and
it falls to zero as the witnesses are repaired — gunbc#9006 is repairing 21 of
them right now — so the evidence had to stop living in the specimens.

The partition, its producer, and the per-identity rows are
docs/plans/receipts/floor-runtime-error-partition-2026-08-23/. Five causal
families; the reference-unavailable subset is 149 of the 164 and every one of
its names IS declared somewhere in the corpus — the undeclared-anywhere class
is EMPTY, so intended compile state never separates on the name not existing.
It separates on where the declaration lives: 126 identities reference a
module-scope `data` in an unimported module, 9 a bare variant or type name, 8
a `fn`, 5 a `test data` in another test file, 1 a type in call position.

WHAT LANDS AS A FIXTURE: HOST-PRIMITIVE-CONTRACT, 11 of the 164. Measured on
compile_dag_rust_emit_check at this head, a host primitive's argument list is
unchecked at compile in every direction — two arguments, zero arguments, and
one argument of the wrong type all compile clean, and the host arm then refuses
each at evaluation with `requires exactly one string argument`. Three REDs
assert the refusal belongs at compile; three positive controls (clean compiles,
broken refuses, the CORRECT one-string call still compiles) make each RED
discriminating rather than a blanket claim. All six measured by execution:
controls true, REDs false. The three are enrolled in floor_expected_red so the
day the contract is checked they PASS and red the build naming themselves.

WHAT DOES NOT LAND, as a measurement rather than an omission: no fixture for
the 149. Both .dag-callable compile-observation surfaces REFUSE that shape
(compile_dag_rust_emit_check false, compile_diagnostic_census blocking) while
the floor's own witness loader ACCEPTS it, because that loader runs
extend_with_bare_reference_closure and resolves the name through the tree
census. A fixture on either surface would be permanently green and cited as
coverage of a class it never touches. Its next-rung trigger is a
compile-observation surface resolving names by the witness loader's rule.

Discriminating control for that claim, executed both ways: a source calling
`argument_form_is_valid(design_argument)` with no imports compiles silent and
throws NoSuchFunction at evaluation; the identical source with
`import gunbc.design_argument { design_argument }` compiles and evaluates true.
The import is the whole discriminator and the compiler says nothing about it.

Enrolment verified by execution: roster length 203, the identity present once.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@briansrls
briansrls merged commit 68c525e into main Aug 23, 2026
1 of 2 checks passed
@briansrls
briansrls deleted the session/neat-deer-718 branch August 23, 2026 14:45
gunbai-bot Bot pushed a commit that referenced this pull request Aug 23, 2026
…protects it

Fixing the ArgvCommand seal unmasked nothing -- this was already visible. With
preparation passing, the fold runs and refuses:

  REQUIRED-FLOOR REFUSAL cause=ExpectedRedIdentityDidNotExecute count=3
  test.claim.compile_accepted_unevaluable_program_control.primitive_call_with_{extra,missing,wrong}_...

gunbc#9022 landed both the module and the enrolment. Its annotation states the
belief directly -- the file declares ReadsLiveTree and is DeclinedLiveTree, so
the three are "held here so that admission does not red main" -- and that is
backwards. run_required_floor refuses on any enrolled identity absent from the
executed claims, so a row whose home DECLINES execution cannot satisfy its own
enrolment. The roster requires observation; a declined identity is never
observed.

Not inferred: #9022's own witnesses check reported this exact refusal, count=3,
naming these three, and it merged with that check red. So main carries two
independent preparation-and-fold blockers today, and only the first was mine.

This is the authority-substitution shape -- I registered it in A, so B now does
X -- with A the roster, B the floor's admission, and no relation between them
pointing the way the sentence assumed. The relation that exists points the other
way.

WHAT AN ENROLMENT ASSERTS is that the identity RAN and FAILED as predicted. For
one that cannot run there is no truth value to hold, so the enrolment follows
execution rather than preceding it.

NOTHING IS HIDDEN. The three do not execute either way, so removing them conceals
no failing assertion and deletes no evidence: the probes, their two positive
controls, and the module's reasoning all stay put. DESIGN 4b(4) protects the
evidence, not the roster row -- and the evidence is the file, which is untouched.

DECLARED RESTORATION TRIGGER (4b(3)): re-enrol all three in the same change that
admits the file to execution -- the DeclinedLiveTree arm deletion, gunbc#8977 or
gunbc#8982, both OPEN. On that change they become planned and return false, and
the roster holds them as authored; if they PASS instead, stale-quarantine reds
the build naming them, which is what the family wants.

Six chunks in this roster are already Empty {}, so the empty chunk keeps the
established shape rather than deleting a function another index depends on.
gunbai-bot Bot pushed a commit that referenced this pull request Aug 23, 2026
…e floor

The ArgvCommand repair in this branch unmasked a second main-red defect that had
never been observed, because every run since it landed died at strict preparation
before the fold could reach it.

gunbc#9022 enrolled three compile_accepted_unevaluable_program_control identities
in the expected-red roster while their file declares ReadsLiveTree, so the
DeclinedLiveTree arm declines them (declined_live=899) and they are never planned.
The floor requires every ENROLLED identity to be observed among the EXECUTED
claims, so the run refuses with cause=ExpectedRedIdentityDidNotExecute count=3.

Chunk 21's own annotation states the opposite belief -- "until it lands they are
held here so that admission does not red main" -- and execution refutes it twice:
on #9022's own run 32644795043, which was merged red, and again on run 32649496046
here, where it was the sole floor refusal once the seal stopped masking it.

The precondition that enrolment was authored against has not landed: gunbc#8977 and
gunbc#8982, which delete the decline arm, are both still open.

The rows are correct and stay in chunk 21. Only their LIVENESS is wrong, so they
join the file's existing exclusion in floor_expected_red_is_live -- the mechanism
already used for the mock-totality family -- which keeps the rows for provenance
while removing them from the live roster.

Verified by execution, not by reading the predicate: each of the three returns
excluded (exit 1) through --claim-run, and an arbitrary unrelated identity returns
live (exit 0), so the predicate discriminates rather than excluding everything.

The exclusion is a coupling, not a note: whoever lands #8977 or #8982 must delete
these three exclusions in the same change, or the rows will execute while excluded,
count as ordinary failures, and red the build.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 23, 2026
…overed

Operator ruling 2026-08-23: kill/quarantine it and find out why. Both halves are
here -- the move, and the measurement that makes this a filed defect rather than
a cost row.

#9031's run 32657761997 was otherwise clean (failed=0, stale_quarantine=0,
interrupted_before_verdict=0) with ONE non-pass:

  COMPLETED-OVER-COST-REQUIREMENT
  qualified_spelling_takes_the_shared_layer   wall_ms=57337 cpu_ms=57193
  [floor-claim-memory] grew rss by 1.22GB (to 11.70GB)

11x the 5000ms executor fail-stop. The fail-stop is doing its job: at 11.70GB
this claim genuinely threatens the process it runs in.

THE SPLIT THAT WAS SUPPOSED TO FIX THIS DID NOTHING, and that is the finding.
#8984's own note records the conjoined two-arm claim at 1.22GB RSS growth
against 0.12GB for the whole rest of the roster, and splits the arms into
separate test fns on the reasoning that two live compile_dag_rust_emit_check
calls sat inside one claim. Measured after the split, the QUALIFIED ARM ALONE
grows 1.22GB -- the identical figure -- and the bare arm appears in no over-cost
or memory line at all. So the entire cost was always the qualified arm. It is
not two compiles; it is the qualified-name resolution path specifically, which
is the path #8984 exists to repair.

WHY QUARANTINE AND NOT A COST ENVELOPE. An envelope large enough to admit 57s
and 1.22GB would admit the defect rather than measure it. The dissolution
condition on this row is therefore the REPAIR, explicitly not an envelope, so
nobody closes it by raising the ceiling.

WHY IT REACHED MAIN UNSEEN. #8984 landed in the batch after the last green run
while main refused at floor PREPARATION on an unrelated ArgvCommand seal break,
so its floor phase never executed and this row never surfaced on its own check.
That is the same masking that hid #9022's roster defect in the same batch -- two
independent defects merged behind one preparation refusal, which is the argument
for consuming every gating cause on your own run rather than only the rows you
meant to change.

WHAT MOVES: the file to dag/test/claim/long/ with its module renamed, one
WitnessExclusionRow carrying the measurement and the local recipe, and the
provider fixture's prose pointer updated so it does not name a module path that
no longer exists.

WHAT DOES NOT MOVE: both arms, their assertions and the whole authored rationale
are untouched. This is a home change and a declared rung drop, not a repair and
not a weakening of what the witness claims.
gunbai-bot Bot added a commit that referenced this pull request Aug 23, 2026
…ather than by widening the seal (#9031)

* Convert the one ArgvCommand site the seal missed, through a builder rather than by widening the seal

main does not compile. `extdeps.exec.command` `ArgvCommand` became `sole_constructor
{ program, arguments }` in #8919, and its carrier states the invariant: "Every
ArgvCommand construction site in the corpus was converted in the same change, because
a partial seal is a dual-authority interval rather than a weaker seal."

One site was not. `gunbc.runner_slot_provision` `observe_runner_slot_members_wet` still
built `ArgvCommand { argv: ["ls", "-1", actions_runner_base_dir] }`, producing four
distinct diagnostics and refusing the floor at strict-preparation — so no witness ran
and no `required-floor` counter line was emitted at all.

Not a missed conversion by that PR. #8992 ADDED this site after #8919 was authored and
before it merged; neither touched the other's lines, so git merged both without a
conflict and the corpus broke on semantics. A clean merge is not coherence.

WHAT WAS DELIBERATELY NOT DONE: `runner_slot_provision` is not added to `argv_command`'s
`admit_callers`. That list is forty named builders, each for ONE operation of ONE tool,
homed in that tool's own extdeps module; admitting a product module would defeat the
wall rather than satisfy it.

A MODELED ALTERNATIVE WAS LOOKED FOR FIRST and does not exist at this layer. `ls -1 |
parse` is a shell-ism, so the right first question was whether the substrate already
answers "what entries are under this path" without shelling out. `dag/extdeps/filesystem`
carries posix `EntryKind` but no listing operation, and the `list_dir` in
`src/v2/extdeps/file_system.dag` is the v2 realization surface, not reachable from a v1-era
`wet` observation running over `LocalExec`. So the builder is authored rather than the
listing being re-modeled, and the call site keeps enumerating BY DIRECTORY — which its own
carrier requires, since probing the desired names could only ever return a subset of what
was already intended and would make an out-of-band slot invisible.

`-1` is baked into the builder with its reason, following `rm_force_command`'s precedent:
ls(1) columnates to a terminal and emits one-per-line to a pipe, so a caller that does not
pass `-1` depends on where its output happens to go. It does not recurse and does not
include dotfiles; a caller needing either needs its own name, not a flags parameter.

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

* Enrolled-but-never-planned is not a parking spot: it refuses the whole floor

The ArgvCommand repair in this branch unmasked a second main-red defect that had
never been observed, because every run since it landed died at strict preparation
before the fold could reach it.

gunbc#9022 enrolled three compile_accepted_unevaluable_program_control identities
in the expected-red roster while their file declares ReadsLiveTree, so the
DeclinedLiveTree arm declines them (declined_live=899) and they are never planned.
The floor requires every ENROLLED identity to be observed among the EXECUTED
claims, so the run refuses with cause=ExpectedRedIdentityDidNotExecute count=3.

Chunk 21's own annotation states the opposite belief -- "until it lands they are
held here so that admission does not red main" -- and execution refutes it twice:
on #9022's own run 32644795043, which was merged red, and again on run 32649496046
here, where it was the sole floor refusal once the seal stopped masking it.

The precondition that enrolment was authored against has not landed: gunbc#8977 and
gunbc#8982, which delete the decline arm, are both still open.

The rows are correct and stay in chunk 21. Only their LIVENESS is wrong, so they
join the file's existing exclusion in floor_expected_red_is_live -- the mechanism
already used for the mock-totality family -- which keeps the rows for provenance
while removing them from the live roster.

Verified by execution, not by reading the predicate: each of the three returns
excluded (exit 1) through --claim-run, and an arbitrary unrelated identity returns
live (exit 0), so the predicate discriminates rather than excluding everything.

The exclusion is a coupling, not a note: whoever lands #8977 or #8982 must delete
these three exclusions in the same change, or the rows will execute while excluded,
count as ordinary failures, and red the build.

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

* The srv4 activation witness re-spelled two programs the seal then moved

Third blocker on main, and the first one visible only after the other two
cleared: with preparation passing and the roster refusal gone, the fold reaches
this row and it returns false.

  FAIL test.claim.runner_host_deploy.srv4_enables_its_declared_runner_instances

The cause is one conjunct, and it is not the width axis this row is otherwise
about:

  && string_contains(s: enable, pattern: "'sudo' 'systemctl' 'enable' '--now'")

That was correct against the hand-built argv the row was written for. #8919
routed runner_enable_command_argv through extdeps.systemd.systemctl
systemctl_enable_now_command, which mints through the sealed argv_command with
sudo_binary_path (/usr/bin/sudo) as the program and inserts sudo's
non-interactive flag -- so the rendered prefix is no longer the four words the
pattern names, and #8919 updated two lines of this file without reaching this
one.

WHAT I CHECKED BEFORE CHANGING ANYTHING, because a witness edited to match the
code it guards is worse than a red one. Quoting was the obvious suspect and it
is NOT the cause: shell_quote single-quotes unconditionally (emit_test's
shell_quote(arg: "plain") == "'plain'" pins it), so the unit-name conjuncts still
match. Admission was the other suspect and it is not the cause either: the
fixture receipts bind correctly on every arm admit_runner_activation checks --
instance host, managed_unit against intended_unit, all six verified flags, pool
host, and slice_unit against intended_compile_pool -- so the command is READY and
`enable` is a real render rather than the refusal arm's "".

THE REPAIR CITES RATHER THAN RE-SPELLS. The old pattern was a third authoring of
facts extdeps.sudo.elevation and extdeps.systemd.systemctl already own, which is
why it rotted without anyone touching it (DESIGN section 3). The conjunct is now
two, deriving the program spellings from those authorities and split because they
assert different things: that activation ELEVATES NON-INTERACTIVELY, and that it
reaches systemctl's ENABLE --NOW.

WHY THIS IS NOT measure() == measure(). `enable` and `--now` stay literal, and
they are the discriminating half: they are systemctl's own operands, spelled
inline by the builder rather than read from any row, so a command that carried
the units without the verb still fails here. What the derived halves buy is that
a future re-homing of the sudo or systemctl spelling moves the assertion with the
authority instead of leaving a fourth copy to rot.

Not verified locally: the same stale-binary limit recorded on the previous commit
applies. CI is the authority.

* join is not a std.types export: the two derived patterns build with concat

Preparation refused on the previous head with a single diagnostic --
  runner_host_deploy_witness_test.dag:4:33: name 'join' not found in module
  'std.types'
-- so the import I added to carry the derived invocation patterns named a symbol
that module does not export. The witness already builds every other composed
pattern with concat and needs no import for it; the two new ones now do the same.

This is my own defect from the previous commit, not new fallout: the repair it
carries is unchanged, only its spelling of string concatenation. The stale-binary
limit recorded there is exactly why it reached CI to be caught -- a local compile
under a binary that predates the seal cannot answer questions about this tree.

* Quarantine the qualified-spelling witness, and file the defect it uncovered

Operator ruling 2026-08-23: kill/quarantine it and find out why. Both halves are
here -- the move, and the measurement that makes this a filed defect rather than
a cost row.

#9031's run 32657761997 was otherwise clean (failed=0, stale_quarantine=0,
interrupted_before_verdict=0) with ONE non-pass:

  COMPLETED-OVER-COST-REQUIREMENT
  qualified_spelling_takes_the_shared_layer   wall_ms=57337 cpu_ms=57193
  [floor-claim-memory] grew rss by 1.22GB (to 11.70GB)

11x the 5000ms executor fail-stop. The fail-stop is doing its job: at 11.70GB
this claim genuinely threatens the process it runs in.

THE SPLIT THAT WAS SUPPOSED TO FIX THIS DID NOTHING, and that is the finding.
#8984's own note records the conjoined two-arm claim at 1.22GB RSS growth
against 0.12GB for the whole rest of the roster, and splits the arms into
separate test fns on the reasoning that two live compile_dag_rust_emit_check
calls sat inside one claim. Measured after the split, the QUALIFIED ARM ALONE
grows 1.22GB -- the identical figure -- and the bare arm appears in no over-cost
or memory line at all. So the entire cost was always the qualified arm. It is
not two compiles; it is the qualified-name resolution path specifically, which
is the path #8984 exists to repair.

WHY QUARANTINE AND NOT A COST ENVELOPE. An envelope large enough to admit 57s
and 1.22GB would admit the defect rather than measure it. The dissolution
condition on this row is therefore the REPAIR, explicitly not an envelope, so
nobody closes it by raising the ceiling.

WHY IT REACHED MAIN UNSEEN. #8984 landed in the batch after the last green run
while main refused at floor PREPARATION on an unrelated ArgvCommand seal break,
so its floor phase never executed and this row never surfaced on its own check.
That is the same masking that hid #9022's roster defect in the same batch -- two
independent defects merged behind one preparation refusal, which is the argument
for consuming every gating cause on your own run rather than only the rows you
meant to change.

WHAT MOVES: the file to dag/test/claim/long/ with its module renamed, one
WitnessExclusionRow carrying the measurement and the local recipe, and the
provider fixture's prose pointer updated so it does not name a module path that
no longer exists.

WHAT DOES NOT MOVE: both arms, their assertions and the whole authored rationale
are untouched. This is a home change and a declared rung drop, not a repair and
not a weakening of what the witness claims.

* Two zero-byte shell artifacts were committed at the repo root

`exit_code` and `{` are both empty files introduced by 96da63f. They are
redirect and brace-expansion debris from an interactive shell, not source, and
nothing references either as a path: the `exit_code` hits in the corpus are
shell-transport OUTPUT FIELD decodings (`exit_code: Int from "exit_code"` in
extdeps.shell.exec and friends), which name a captured field, not a file.

Removed rather than ignored. A .gitignore rule does not untrack a path already
in the branch, and leaving them would land two junk files in the repo root on
merge.

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

---------

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: Brian Searls <briansearls1@gmail.com>
briansrls pushed a commit that referenced this pull request Aug 23, 2026
* WIP: MAIN RED #4: eight runner-slot/fleet-capacity witnesses return Bool(fals

* Fix record-like if condition brace parsing

* Unenrol the seventeen rows this fix made pass, and keep the four beside them that it did not

The floor reported seventeen v2.test.claim.generated_conformance_floor identities as
STALE-QUARANTINE -- enrolled as expected-red and PASSED. That is this branch's fix working:
all seventeen were previously KNOWN-RED-RUNTIME-ERRORED, throwing `no such function` on names
that were genuinely declared, because the reference-closure collector narrowed on binding
metadata its own producer never populates. Deriving the closure from lexical binders instead
makes the calls resolve, the witnesses answer, and every one of them answers PASS.

The two arms are not symmetric and that is why this reds the build. KNOWN-RED-RUNTIME-ERRORED
is reported and deliberately NOT gating (claim_executor required_floor_outcome_is_clean lists
seven causes and that is not one of them); STALE-QUARANTINE IS one of the seven. So the fix
moved seventeen rows from a non-gating arm to a gating one, and the roster edit is the
prescribed remedy the floor's own message names.

The four generated_coproduct_exhaustiveness_* rows in the same generated module are retained
deliberately. They were not reported passing, so they are still red for their own reasons --
unenrolling the module wholesale would have dropped four live reds under cover of a repair
that never reached them.

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

* Convert the one ArgvCommand site the seal missed, through a builder rather than by widening the seal

main does not compile. `extdeps.exec.command` `ArgvCommand` became `sole_constructor
{ program, arguments }` in #8919, and its carrier states the invariant: "Every
ArgvCommand construction site in the corpus was converted in the same change, because
a partial seal is a dual-authority interval rather than a weaker seal."

One site was not. `gunbc.runner_slot_provision` `observe_runner_slot_members_wet` still
built `ArgvCommand { argv: ["ls", "-1", actions_runner_base_dir] }`, producing four
distinct diagnostics and refusing the floor at strict-preparation — so no witness ran
and no `required-floor` counter line was emitted at all.

Not a missed conversion by that PR. #8992 ADDED this site after #8919 was authored and
before it merged; neither touched the other's lines, so git merged both without a
conflict and the corpus broke on semantics. A clean merge is not coherence.

WHAT WAS DELIBERATELY NOT DONE: `runner_slot_provision` is not added to `argv_command`'s
`admit_callers`. That list is forty named builders, each for ONE operation of ONE tool,
homed in that tool's own extdeps module; admitting a product module would defeat the
wall rather than satisfy it.

A MODELED ALTERNATIVE WAS LOOKED FOR FIRST and does not exist at this layer. `ls -1 |
parse` is a shell-ism, so the right first question was whether the substrate already
answers "what entries are under this path" without shelling out. `dag/extdeps/filesystem`
carries posix `EntryKind` but no listing operation, and the `list_dir` in
`src/v2/extdeps/file_system.dag` is the v2 realization surface, not reachable from a v1-era
`wet` observation running over `LocalExec`. So the builder is authored rather than the
listing being re-modeled, and the call site keeps enumerating BY DIRECTORY — which its own
carrier requires, since probing the desired names could only ever return a subset of what
was already intended and would make an out-of-band slot invisible.

`-1` is baked into the builder with its reason, following `rm_force_command`'s precedent:
ls(1) columnates to a terminal and emits one-per-line to a pipe, so a caller that does not
pass `-1` depends on where its output happens to go. It does not recurse and does not
include dotfiles; a caller needing either needs its own name, not a flags parameter.

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

* Handle record-like conditions on operator RHS

* An enrolled identity that cannot execute is what reds main, not what protects it

Fixing the ArgvCommand seal unmasked nothing -- this was already visible. With
preparation passing, the fold runs and refuses:

  REQUIRED-FLOOR REFUSAL cause=ExpectedRedIdentityDidNotExecute count=3
  test.claim.compile_accepted_unevaluable_program_control.primitive_call_with_{extra,missing,wrong}_...

gunbc#9022 landed both the module and the enrolment. Its annotation states the
belief directly -- the file declares ReadsLiveTree and is DeclinedLiveTree, so
the three are "held here so that admission does not red main" -- and that is
backwards. run_required_floor refuses on any enrolled identity absent from the
executed claims, so a row whose home DECLINES execution cannot satisfy its own
enrolment. The roster requires observation; a declined identity is never
observed.

Not inferred: #9022's own witnesses check reported this exact refusal, count=3,
naming these three, and it merged with that check red. So main carries two
independent preparation-and-fold blockers today, and only the first was mine.

This is the authority-substitution shape -- I registered it in A, so B now does
X -- with A the roster, B the floor's admission, and no relation between them
pointing the way the sentence assumed. The relation that exists points the other
way.

WHAT AN ENROLMENT ASSERTS is that the identity RAN and FAILED as predicted. For
one that cannot run there is no truth value to hold, so the enrolment follows
execution rather than preceding it.

NOTHING IS HIDDEN. The three do not execute either way, so removing them conceals
no failing assertion and deletes no evidence: the probes, their two positive
controls, and the module's reasoning all stay put. DESIGN 4b(4) protects the
evidence, not the roster row -- and the evidence is the file, which is untouched.

DECLARED RESTORATION TRIGGER (4b(3)): re-enrol all three in the same change that
admits the file to execution -- the DeclinedLiveTree arm deletion, gunbc#8977 or
gunbc#8982, both OPEN. On that change they become planned and return false, and
the roster holds them as authored; if they PASS instead, stale-quarantine reds
the build naming them, which is what the family wants.

Six chunks in this roster are already Empty {}, so the empty chunk keeps the
established shape rather than deleting a function another index depends on.

* Enrolled-but-never-planned is not a parking spot: it refuses the whole floor

The ArgvCommand repair in this branch unmasked a second main-red defect that had
never been observed, because every run since it landed died at strict preparation
before the fold could reach it.

gunbc#9022 enrolled three compile_accepted_unevaluable_program_control identities
in the expected-red roster while their file declares ReadsLiveTree, so the
DeclinedLiveTree arm declines them (declined_live=899) and they are never planned.
The floor requires every ENROLLED identity to be observed among the EXECUTED
claims, so the run refuses with cause=ExpectedRedIdentityDidNotExecute count=3.

Chunk 21's own annotation states the opposite belief -- "until it lands they are
held here so that admission does not red main" -- and execution refutes it twice:
on #9022's own run 32644795043, which was merged red, and again on run 32649496046
here, where it was the sole floor refusal once the seal stopped masking it.

The precondition that enrolment was authored against has not landed: gunbc#8977 and
gunbc#8982, which delete the decline arm, are both still open.

The rows are correct and stay in chunk 21. Only their LIVENESS is wrong, so they
join the file's existing exclusion in floor_expected_red_is_live -- the mechanism
already used for the mock-totality family -- which keeps the rows for provenance
while removing them from the live roster.

Verified by execution, not by reading the predicate: each of the three returns
excluded (exit 1) through --claim-run, and an arbitrary unrelated identity returns
live (exit 0), so the predicate discriminates rather than excluding everything.

The exclusion is a coupling, not a note: whoever lands #8977 or #8982 must delete
these three exclusions in the same change, or the rows will execute while excluded,
count as ordinary failures, and red the build.

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

* The srv4 activation witness re-spelled two programs the seal then moved

Third blocker on main, and the first one visible only after the other two
cleared: with preparation passing and the roster refusal gone, the fold reaches
this row and it returns false.

  FAIL test.claim.runner_host_deploy.srv4_enables_its_declared_runner_instances

The cause is one conjunct, and it is not the width axis this row is otherwise
about:

  && string_contains(s: enable, pattern: "'sudo' 'systemctl' 'enable' '--now'")

That was correct against the hand-built argv the row was written for. #8919
routed runner_enable_command_argv through extdeps.systemd.systemctl
systemctl_enable_now_command, which mints through the sealed argv_command with
sudo_binary_path (/usr/bin/sudo) as the program and inserts sudo's
non-interactive flag -- so the rendered prefix is no longer the four words the
pattern names, and #8919 updated two lines of this file without reaching this
one.

WHAT I CHECKED BEFORE CHANGING ANYTHING, because a witness edited to match the
code it guards is worse than a red one. Quoting was the obvious suspect and it
is NOT the cause: shell_quote single-quotes unconditionally (emit_test's
shell_quote(arg: "plain") == "'plain'" pins it), so the unit-name conjuncts still
match. Admission was the other suspect and it is not the cause either: the
fixture receipts bind correctly on every arm admit_runner_activation checks --
instance host, managed_unit against intended_unit, all six verified flags, pool
host, and slice_unit against intended_compile_pool -- so the command is READY and
`enable` is a real render rather than the refusal arm's "".

THE REPAIR CITES RATHER THAN RE-SPELLS. The old pattern was a third authoring of
facts extdeps.sudo.elevation and extdeps.systemd.systemctl already own, which is
why it rotted without anyone touching it (DESIGN section 3). The conjunct is now
two, deriving the program spellings from those authorities and split because they
assert different things: that activation ELEVATES NON-INTERACTIVELY, and that it
reaches systemctl's ENABLE --NOW.

WHY THIS IS NOT measure() == measure(). `enable` and `--now` stay literal, and
they are the discriminating half: they are systemctl's own operands, spelled
inline by the builder rather than read from any row, so a command that carried
the units without the verb still fails here. What the derived halves buy is that
a future re-homing of the sudo or systemctl spelling moves the assertion with the
authority instead of leaving a fourth copy to rot.

Not verified locally: the same stale-binary limit recorded on the previous commit
applies. CI is the authority.

* Repin the srv4 enable witness on the grounded sudo spelling, and stop its refusal arm from erasing the cause

srv4_enables_its_declared_runner_instances was red on main, and not on the
roster/units join it exists to check. Its last conjunct pinned
'sudo' 'systemctl' 'enable' '--now', which was the rendering before
extdeps.sudo.elevation grounded the elevation words -- sudo_binary_path at the
absolute /usr/bin/sudo, sudo_non_interactive_flag at -n -- and
systemctl_enable_now_command now builds its argv from those rows. Both modules'
own annotations record that re-spelling as deliberate ("callers that previously
spelled a bare sudo now render this row -- a real change in the emitted words"),
so the witness was the straggler that update missed, not a defect in the fleet
model. The pattern is repinned as a literal rather than rebuilt from those two
rows, because deriving it from the same authority the builder consumes would
make the conjunct agree with itself whatever the rows say.

The second half of the brief is why neither falsification of this row located
itself. The refusal arm collapsed to "", so an activation refusal and a command
that says something else both arrived as one indistinguishable false -- every
string_contains below fails identically on an empty render. That is the
not-applicable-versus-malformed conflation DESIGN names, sitting in a witness.
Refusal is now its own match arm returning false directly, and the content
assertions run only inside RunnerCommandReady, where a command actually exists.
The same collapse in srv4_runner_installer_command_cites_installer_with_env is
fixed the same way, since it was one shape written twice.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014oG2tMMAxgZeAQxDjvNsFm

* Remove trailing whitespace from expected-red roster

* join is not a std.types export: the two derived patterns build with concat

Preparation refused on the previous head with a single diagnostic --
  runner_host_deploy_witness_test.dag:4:33: name 'join' not found in module
  'std.types'
-- so the import I added to carry the derived invocation patterns named a symbol
that module does not export. The witness already builds every other composed
pattern with concat and needs no import for it; the two new ones now do the same.

This is my own defect from the previous commit, not new fallout: the repair it
carries is unchanged, only its spelling of string concatenation. The stale-binary
limit recorded there is exactly why it reached CI to be caught -- a local compile
under a binary that predates the seal cannot answer questions about this tree.

* Drop the enable-conjunct change: #9031 owns that row, and the derivation ruling is right

RULING ACCEPTED (swift-badger-524). #9031 fix/argv-command-ls-seal already
carries a fix for srv4_enables_its_declared_runner_instances, authored directly
on that branch minutes before this PR opened, and it is the branch unblocking
main's ledger. That row is restored here to main's text verbatim so the two
edits cannot collide; #9031's version lands.

I WAS WRONG ABOUT THE DERIVATION AND THE REASON MATTERS. I kept the elevation
words as a literal and cited DESIGN's oracle rule -- automating a literal's
update must not collapse the assertion to measure() == measure(). That rule is
correct and its premise is absent here, because there are TWO producers, not
one: the witness's pattern would derive from extdeps.sudo.elevation and
extdeps.systemd.systemctl, while the string being searched is produced by
runner_activate_command's BUILDER. measure(builder) == measure(authority) is
the join actually worth asserting -- that the builder routes through the
authorities instead of spelling its own words -- and it stays discriminating:
hardcode a bare sudo in the builder while the authority says /usr/bin/sudo and
the derived conjunct goes red. The collapse I feared needs the pattern derived
from the builder's own output, which nobody proposed.

Worse, my literal had the failure mode I was avoiding, pointing the other way: a
pinned 'sudo' 'systemctl' 'enable' '--now' is a THIRD authoring of facts two
extdeps modules already own, and it rotted the moment activation routed through
systemctl_enable_now_command -- which is why the row was red at all. Repinning
it buys one green run and re-arms the trap. #9031 derives what an authority owns
and leaves 'enable' and '--now' literal, because those are systemctl's own
operands that the builder spells inline and no row owns. That is the general
line and it is better than what I wrote.

WHAT REMAINS IS THE HALF NOTHING ELSE CARRIES. The installer witness rendered
RunnerCommandRefused as "" and then pattern-matched the empty string, so a
REFUSAL and a WRONG RENDER produced the same false with opposite repairs -- the
not-applicable-versus-malformed conflation. The assertions now run inside the
Ready arm and the refusal arm returns false on its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014oG2tMMAxgZeAQxDjvNsFm

* Revert "Remove trailing whitespace from expected-red roster"

This reverts commit 0279359.

* Revert "Merge remote-tracking branch 'origin/pr-9020' into session/swift-heron-558"

This reverts commit fedaca4, reversing
changes made to 7981ec6.

* Name the no-brace parser retry debt

* Reconcile expected-red liveness authority

* The 57s qualified-spelling claim is a whole-tree policy resolve, not name resolution

The floor line that opened this (qualified_spelling_takes_the_shared_layer,
wall_ms=57337, +1.22GB, bare arm free) reads as "qualified-name resolution is
expensive". It is not. Qualified resolution is a map_get.

Measured, four orderings plus a discriminating control: a qualified PATTERN HEAD
costs nothing, and the premium lands on whichever claim first compiles a qualified
TYPE ANNOTATION -- once per process, then 5ms forever after.

The mechanism is severity classification, not resolution. A qualified annotation's
authored name misses env.source_visible_names (which carries the bare imported
names), so the masked type-ref arm emits an advisory UnlistedImportUse. Classifying
that one diagnostic calls compile_clean_unlisted_import_use_blocks_from_policy,
which resolves and typechecks a whole separate entry closure over
default_source_roots() -- the whole tree -- to evaluate one nullary Bool. A bare
annotation emits no such diagnostic and skips it; a qualified pattern head never
enters that arm.

This is gunbc.ci_spec's already-documented cost B from 2026-07-25, whose dissolve-on
(scope the policy resolve to the policy module's own import closure) was never
discharged. That note measured 57.8s for a green compile paying this tail against
the floor's 57337ms.

Shape, answering the brief: constant per process, independent of the subject
compiled, and corpus-denominated. Same probe, roots varied: 216ms warm against
44886ms when from_policy's whole-tree root set diverges from the caller's and pays a
cold load -- 44.9s locally against 57.3s on the floor.

Diagnosis only; no repair, and the 1.22GB is reported as consistent-with rather than
measured, since the witness is quarantined and the floor line was not re-run.

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

* Scope the compile-clean policy read to its own import closure, refusing rather than widening

Discharges the cost-B half of gunbc.ci_spec gunbc_ci_floor_batch_clamp_note's
dissolve-on, which has named this exact repair since 2026-07-25 and was never
landed. No second row is filed beside it: the obligation is discharged in place,
because landing the fix while leaving its obligation open would be two authorities
for one fact.

compile_clean_unlisted_import_use_blocks_from_policy resolved and typechecked an
entry closure over default_source_roots() -- the whole tree -- to evaluate one
nullary Bool. That is not merely oversized (the policy module has three imports);
it is a function answering a question about the caller's world by consulting a
different one, which is why it presents as cost but is correctness-shaped, and why
"n is small here" was never available.

It now assembles the policy entry's own import closure and resolves that explicit
source set. Every arm that cannot produce the exact closure REFUSES with a located
message naming the module and the path. There is deliberately no whole-tree
fallback: that arm would restore today's cost, zero the deficit's frequency by
construction, and make the widening unrankable ever after (DESIGN section 5). It is
a new closure builder rather than a reuse of resolve_virtual_source_with_imports
because that BFS silently SKIPS an unresolvable import -- a silent skip here would
answer the policy question from a graph missing the module the answer depends on.

MEASURED, same probe and orderings, all probes PASS so the narrowed closure still
returns the policy Bool:

  roots dag only     C first qualified   44886ms -> 109ms
  roots dag + src/v2 C first qualified     216ms -> 151ms

The qualified/bare asymmetry is gone rather than reduced: on the cold root set the
qualified arm is now CHEAPER than the bare one.

RESIDUE, reported rather than absorbed: the bare arm's 12967ms on the dag-only root
set did not move (12881ms). The bare arm pays it too, so it was never part of the
qualified asymmetry and this repair does not touch it.

NOT UPGRADED: the floor's 1.22GB is still unattributed by execution. If the memory
line survives this repair that is a second defect to find, not one to absorb here.

v1 freeze admission: PURPOSE test (operator ruling 2026-08-20) -- a defect repair on
a path the required floor executes every run, not growth on a v1 surface for v1's
own sake.

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

---------

Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Aug 24, 2026
… break reached main and no gate could see it (#9035)

* Main emission is refusing on a trailing annotation, and CI cannot see it

`gunbc compile --entry src/v2/compiler/03_ingest.dag` REFUSES on current main
(faf6583) with `EMIT_REFUSE` and no cargo log at all. Measured this morning
at 907f19c the same entry emitted 177 files and 316 coded errors, so the
board's subject stopped being producible at some point in today's merges.

The cause is one file. §4c admits an annotation only as a standalone leading
`//` block attached to a module-scope declaration; #8919 left a 62-line block at
end-of-file with no item following it, and the compiler correctly refuses every
span of it -- "source annotation names no subject: no module item follows it".
A corpus-wide scan finds exactly one such file, so the population is closed.

The repair moves the block above the file's final declaration. Every annotation
line is preserved verbatim (diff of sorted `//` lines is one added `//`
separator); no prose is rewritten, dropped, or summarised, because a block
deleted for one reason takes everything in it unless its contents are enumerated
first.

WHAT THIS SAYS ABOUT THE GATE, which matters more than the fix. This is the
SECOND instance of this class today: #8976 landed an indented `//` inside a
match arm this morning and broke the floor corpus-wide for 74 minutes. That one
was caught because the file was floor-enrolled. THIS one sits in
dag/test/manual/, which no required phase parses -- the required run's three
phases are the src/v1 `.dag` parse sweep, required-regen, and the witness floor,
and none of them compiles a v2 entry. So an emission-breaking change landed on
main and every gate stayed green.

RUNG, honestly: this change is a repair of one instance and NOT a climb. The
class remains writable and undetected. Its next-rung trigger is a required phase
that compiles at least one v2 entry -- the emission path has no gate at all
today, which is why the only instrument that found this was a hand-run probe.

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

* Convert the one ArgvCommand site the seal missed, through a builder rather than by widening the seal

main does not compile. `extdeps.exec.command` `ArgvCommand` became `sole_constructor
{ program, arguments }` in #8919, and its carrier states the invariant: "Every
ArgvCommand construction site in the corpus was converted in the same change, because
a partial seal is a dual-authority interval rather than a weaker seal."

One site was not. `gunbc.runner_slot_provision` `observe_runner_slot_members_wet` still
built `ArgvCommand { argv: ["ls", "-1", actions_runner_base_dir] }`, producing four
distinct diagnostics and refusing the floor at strict-preparation — so no witness ran
and no `required-floor` counter line was emitted at all.

Not a missed conversion by that PR. #8992 ADDED this site after #8919 was authored and
before it merged; neither touched the other's lines, so git merged both without a
conflict and the corpus broke on semantics. A clean merge is not coherence.

WHAT WAS DELIBERATELY NOT DONE: `runner_slot_provision` is not added to `argv_command`'s
`admit_callers`. That list is forty named builders, each for ONE operation of ONE tool,
homed in that tool's own extdeps module; admitting a product module would defeat the
wall rather than satisfy it.

A MODELED ALTERNATIVE WAS LOOKED FOR FIRST and does not exist at this layer. `ls -1 |
parse` is a shell-ism, so the right first question was whether the substrate already
answers "what entries are under this path" without shelling out. `dag/extdeps/filesystem`
carries posix `EntryKind` but no listing operation, and the `list_dir` in
`src/v2/extdeps/file_system.dag` is the v2 realization surface, not reachable from a v1-era
`wet` observation running over `LocalExec`. So the builder is authored rather than the
listing being re-modeled, and the call site keeps enumerating BY DIRECTORY — which its own
carrier requires, since probing the desired names could only ever return a subset of what
was already intended and would make an out-of-band slot invisible.

`-1` is baked into the builder with its reason, following `rm_force_command`'s precedent:
ls(1) columnates to a terminal and emits one-per-line to a pipe, so a caller that does not
pass `-1` depends on where its output happens to go. It does not recurse and does not
include dotfiles; a caller needing either needs its own name, not a flags parameter.

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

* Enrolled-but-never-planned is not a parking spot: it refuses the whole floor

The ArgvCommand repair in this branch unmasked a second main-red defect that had
never been observed, because every run since it landed died at strict preparation
before the fold could reach it.

gunbc#9022 enrolled three compile_accepted_unevaluable_program_control identities
in the expected-red roster while their file declares ReadsLiveTree, so the
DeclinedLiveTree arm declines them (declined_live=899) and they are never planned.
The floor requires every ENROLLED identity to be observed among the EXECUTED
claims, so the run refuses with cause=ExpectedRedIdentityDidNotExecute count=3.

Chunk 21's own annotation states the opposite belief -- "until it lands they are
held here so that admission does not red main" -- and execution refutes it twice:
on #9022's own run 32644795043, which was merged red, and again on run 32649496046
here, where it was the sole floor refusal once the seal stopped masking it.

The precondition that enrolment was authored against has not landed: gunbc#8977 and
gunbc#8982, which delete the decline arm, are both still open.

The rows are correct and stay in chunk 21. Only their LIVENESS is wrong, so they
join the file's existing exclusion in floor_expected_red_is_live -- the mechanism
already used for the mock-totality family -- which keeps the rows for provenance
while removing them from the live roster.

Verified by execution, not by reading the predicate: each of the three returns
excluded (exit 1) through --claim-run, and an arbitrary unrelated identity returns
live (exit 0), so the predicate discriminates rather than excluding everything.

The exclusion is a coupling, not a note: whoever lands #8977 or #8982 must delete
these three exclusions in the same change, or the rows will execute while excluded,
count as ordinary failures, and red the build.

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

* A v2-emission phase behind its own entry point: one entry compiled, refusing only where no tree comes out

The 2026-08-23 break: `gunbc compile --source-root dag --source-root src/v2 --entry
src/v2/compiler/03_ingest.dag` refused outright on main for hours while every required
phase stayed green. The required run parses src/v1 .dag, compares the regen mirrors and
folds the witness floor; none of the three compiles a v2 entry, so the emission path had
no observer. The specimen was a trailing `//` annotation block with no declaration after
it, authored under dag/test/manual/, which no required phase reads either.

`claim_executor --required-v2-emission` compiles the entries named by
`gunbc.ci_layer_roots` `required_v2_emission_entries` and stops the line on the compiler's
own refusal authority (`v1_compiler_compile` `stage0_self_compile_refusal_message`) — a
blocking diagnostic, or an empty emitted file set. Advisory diagnostics are counted and
never refused on: 03_ingest carries 503 of them today, so a gate on any diagnostic would
be permanently red.

`--required-v2-emission-selftest` is the phase's executing evidence: two controlled
fixture roots differing in one thing, the red one carrying the real specimen and the green
one the same block moved above its declaration. Red must refuse on the annotation cause;
green must emit. Mutation-confirmed — moving the red block above a declaration makes the
selftest FAIL.

NOT enrolled in `--required-ci` or witnesses.yml: changing what every PR must pass is an
operator decision, and the enrolment question goes up with its measured cost attached.

* The srv4 activation witness re-spelled two programs the seal then moved

Third blocker on main, and the first one visible only after the other two
cleared: with preparation passing and the roster refusal gone, the fold reaches
this row and it returns false.

  FAIL test.claim.runner_host_deploy.srv4_enables_its_declared_runner_instances

The cause is one conjunct, and it is not the width axis this row is otherwise
about:

  && string_contains(s: enable, pattern: "'sudo' 'systemctl' 'enable' '--now'")

That was correct against the hand-built argv the row was written for. #8919
routed runner_enable_command_argv through extdeps.systemd.systemctl
systemctl_enable_now_command, which mints through the sealed argv_command with
sudo_binary_path (/usr/bin/sudo) as the program and inserts sudo's
non-interactive flag -- so the rendered prefix is no longer the four words the
pattern names, and #8919 updated two lines of this file without reaching this
one.

WHAT I CHECKED BEFORE CHANGING ANYTHING, because a witness edited to match the
code it guards is worse than a red one. Quoting was the obvious suspect and it
is NOT the cause: shell_quote single-quotes unconditionally (emit_test's
shell_quote(arg: "plain") == "'plain'" pins it), so the unit-name conjuncts still
match. Admission was the other suspect and it is not the cause either: the
fixture receipts bind correctly on every arm admit_runner_activation checks --
instance host, managed_unit against intended_unit, all six verified flags, pool
host, and slice_unit against intended_compile_pool -- so the command is READY and
`enable` is a real render rather than the refusal arm's "".

THE REPAIR CITES RATHER THAN RE-SPELLS. The old pattern was a third authoring of
facts extdeps.sudo.elevation and extdeps.systemd.systemctl already own, which is
why it rotted without anyone touching it (DESIGN section 3). The conjunct is now
two, deriving the program spellings from those authorities and split because they
assert different things: that activation ELEVATES NON-INTERACTIVELY, and that it
reaches systemctl's ENABLE --NOW.

WHY THIS IS NOT measure() == measure(). `enable` and `--now` stay literal, and
they are the discriminating half: they are systemctl's own operands, spelled
inline by the builder rather than read from any row, so a command that carried
the units without the verb still fails here. What the derived halves buy is that
a future re-homing of the sudo or systemctl spelling moves the assertion with the
authority instead of leaving a fourth copy to rot.

Not verified locally: the same stale-binary limit recorded on the previous commit
applies. CI is the authority.

* One emission producer for the board and the gate, a three-state disposition, and enrolment as a required phase

Finding 1 (the gate must consume the same producer as the board): it did not. The phase
was a second caller reproducing the closure load, the census assembly, the refusal check
and the silent-pick gate beside `gunbc compile`'s — and had already drifted on one of the
three parameters, resolving under the strict pool index where the board runs
primary-precedence. The transaction now lives in `cli_run` `compile_entry_emission`, and
BOTH the CLI's `--entry` single-target arm and the required phase call it. Verified by
execution that the CLI path is unchanged: abi 4/3847/9, and the board's own invocation on
03_ingest emits 177 by the `compiled:` line with 0 blocking / 503 advisory, exit 0.

Finding 2 (a preparation refusal must not render as emitted=0 blocking=0): `Option<refusal>`
was a two-state carrier expressing three. `EntryEmissionDisposition` is now
Completed / Refused { phase, cause } / NotExecuted { earlier_phase, cause }, the tag is ON
the counts line, and the count fields read `n/a` — deliberately not 0 — on any path that
never ran. All three arms confirmed by execution.

The invariant is emission COMPLETED, never a file count: a legitimate compiler change may
alter closure size, so `emitted == 177` would be a change detector.

ENROLLED as required-ci phase 3, ordered ahead of the floor, on the relayed operator
ruling. The phases stay independent — every one runs after an earlier failure — so this is
report order, not an early prerequisite; making it one is a scheduling decision left to the
operator with the number attached. Dissolution trigger carried on
`gunbc.ci_layer_roots` `required_v2_emission_dissolution`.

* Rewrite the standalone-entry-point comment that still said NOT ENROLLED, and name the enrolment authority beside the dissolution row

The comment beside --required-v2-emission-selftest was written before the enrolment and
survived the revision that added phase 3, so the diff carried prose asserting the phase is
opt-in beside code making it required. Rewritten, not annotated: two accounts of one fact
is what produced the contradiction. The ci_layer_roots row now states the enrolment
authority separately from the dissolution condition — how the gate ends is not the
admission that created it.

* join is not a std.types export: the two derived patterns build with concat

Preparation refused on the previous head with a single diagnostic --
  runner_host_deploy_witness_test.dag:4:33: name 'join' not found in module
  'std.types'
-- so the import I added to carry the derived invocation patterns named a symbol
that module does not export. The witness already builds every other composed
pattern with concat and needs no import for it; the two new ones now do the same.

This is my own defect from the previous commit, not new fallout: the repair it
carries is unchanged, only its spelling of string concatenation. The stale-binary
limit recorded there is exactly why it reached CI to be caught -- a local compile
under a binary that predates the seal cannot answer questions about this tree.

* Ground the selftest's expected refusal on the typed variant's message authority, not a spelled literal

Review 55128 named the coupling: matching `cause.contains("source annotation names no
subject")` is a second spelling of a sentence `std_source_annotation`
`annotation_attachment_refusal_message` owns, and a rewording silently invalidates it. The
expected sentence is now ASKED FOR from that authority, keyed on the typed variant
`UnattachedAtScopeEnd` the fixture provokes, so a rewording moves both sides together.

Confirmed by execution in both mutation directions: a legal red fixture fails with 'did not
refuse', and a fixture refusing for an unrelated cause fails with the grounded sentence
quoted in the message.

* Restore an unrelated function my splice deleted, and build the module index once instead of twice

TWO REVIEW ITEMS FROM review 55167, and the first is a defect in this PR rather than a
suggestion. `declared_import_closure_live_paths` — a `#[cfg(feature = "test_hooks")]` host
twin for the Class B declared-import controls — was DELETED BY ACCIDENT: the edit that
inserted the emission transaction spliced over a region that ended past it, and nothing
failed because it is behind a feature gate with no current caller. The review read it as
intentional and rationalised it. It is restored verbatim; the diff against the merge base
now removes zero lines.

The second: `compile_entry_emission` built the source index twice — once inside
`load_sources_for_entry_with_pool_index` and once for the census fill — parsing ~3,800
modules per invocation for the second copy. It now builds one `MultiEntryIndex` and hands
it to both the closure loader and the census, which also removes the possibility that the
two are computed against different populations. Strict routes through
`process_shared_index` so a second `--entry` compile in one process is a cache hit.

Behaviour identical by execution: abi still 4 closure / 3847 census / 9 emitted, selftest
green. NO SPEEDUP IS CLAIMED — measured 134s against 126s before, inside this host's noise;
the change stands on removing the duplicate parse and the second population, not on a
number I did not observe.

---------

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 <briansearls1@gmail.com>
briansrls added a commit that referenced this pull request Aug 25, 2026
…red rounds (#9039)

* Convert the one ArgvCommand site the seal missed, through a builder rather than by widening the seal

main does not compile. `extdeps.exec.command` `ArgvCommand` became `sole_constructor
{ program, arguments }` in #8919, and its carrier states the invariant: "Every
ArgvCommand construction site in the corpus was converted in the same change, because
a partial seal is a dual-authority interval rather than a weaker seal."

One site was not. `gunbc.runner_slot_provision` `observe_runner_slot_members_wet` still
built `ArgvCommand { argv: ["ls", "-1", actions_runner_base_dir] }`, producing four
distinct diagnostics and refusing the floor at strict-preparation — so no witness ran
and no `required-floor` counter line was emitted at all.

Not a missed conversion by that PR. #8992 ADDED this site after #8919 was authored and
before it merged; neither touched the other's lines, so git merged both without a
conflict and the corpus broke on semantics. A clean merge is not coherence.

WHAT WAS DELIBERATELY NOT DONE: `runner_slot_provision` is not added to `argv_command`'s
`admit_callers`. That list is forty named builders, each for ONE operation of ONE tool,
homed in that tool's own extdeps module; admitting a product module would defeat the
wall rather than satisfy it.

A MODELED ALTERNATIVE WAS LOOKED FOR FIRST and does not exist at this layer. `ls -1 |
parse` is a shell-ism, so the right first question was whether the substrate already
answers "what entries are under this path" without shelling out. `dag/extdeps/filesystem`
carries posix `EntryKind` but no listing operation, and the `list_dir` in
`src/v2/extdeps/file_system.dag` is the v2 realization surface, not reachable from a v1-era
`wet` observation running over `LocalExec`. So the builder is authored rather than the
listing being re-modeled, and the call site keeps enumerating BY DIRECTORY — which its own
carrier requires, since probing the desired names could only ever return a subset of what
was already intended and would make an out-of-band slot invisible.

`-1` is baked into the builder with its reason, following `rm_force_command`'s precedent:
ls(1) columnates to a terminal and emits one-per-line to a pipe, so a caller that does not
pass `-1` depends on where its output happens to go. It does not recurse and does not
include dotfiles; a caller needing either needs its own name, not a flags parameter.

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

* Enrolled-but-never-planned is not a parking spot: it refuses the whole floor

The ArgvCommand repair in this branch unmasked a second main-red defect that had
never been observed, because every run since it landed died at strict preparation
before the fold could reach it.

gunbc#9022 enrolled three compile_accepted_unevaluable_program_control identities
in the expected-red roster while their file declares ReadsLiveTree, so the
DeclinedLiveTree arm declines them (declined_live=899) and they are never planned.
The floor requires every ENROLLED identity to be observed among the EXECUTED
claims, so the run refuses with cause=ExpectedRedIdentityDidNotExecute count=3.

Chunk 21's own annotation states the opposite belief -- "until it lands they are
held here so that admission does not red main" -- and execution refutes it twice:
on #9022's own run 32644795043, which was merged red, and again on run 32649496046
here, where it was the sole floor refusal once the seal stopped masking it.

The precondition that enrolment was authored against has not landed: gunbc#8977 and
gunbc#8982, which delete the decline arm, are both still open.

The rows are correct and stay in chunk 21. Only their LIVENESS is wrong, so they
join the file's existing exclusion in floor_expected_red_is_live -- the mechanism
already used for the mock-totality family -- which keeps the rows for provenance
while removing them from the live roster.

Verified by execution, not by reading the predicate: each of the three returns
excluded (exit 1) through --claim-run, and an arbitrary unrelated identity returns
live (exit 0), so the predicate discriminates rather than excluding everything.

The exclusion is a coupling, not a note: whoever lands #8977 or #8982 must delete
these three exclusions in the same change, or the rows will execute while excluded,
count as ordinary failures, and red the build.

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

* The srv4 activation witness re-spelled two programs the seal then moved

Third blocker on main, and the first one visible only after the other two
cleared: with preparation passing and the roster refusal gone, the fold reaches
this row and it returns false.

  FAIL test.claim.runner_host_deploy.srv4_enables_its_declared_runner_instances

The cause is one conjunct, and it is not the width axis this row is otherwise
about:

  && string_contains(s: enable, pattern: "'sudo' 'systemctl' 'enable' '--now'")

That was correct against the hand-built argv the row was written for. #8919
routed runner_enable_command_argv through extdeps.systemd.systemctl
systemctl_enable_now_command, which mints through the sealed argv_command with
sudo_binary_path (/usr/bin/sudo) as the program and inserts sudo's
non-interactive flag -- so the rendered prefix is no longer the four words the
pattern names, and #8919 updated two lines of this file without reaching this
one.

WHAT I CHECKED BEFORE CHANGING ANYTHING, because a witness edited to match the
code it guards is worse than a red one. Quoting was the obvious suspect and it
is NOT the cause: shell_quote single-quotes unconditionally (emit_test's
shell_quote(arg: "plain") == "'plain'" pins it), so the unit-name conjuncts still
match. Admission was the other suspect and it is not the cause either: the
fixture receipts bind correctly on every arm admit_runner_activation checks --
instance host, managed_unit against intended_unit, all six verified flags, pool
host, and slice_unit against intended_compile_pool -- so the command is READY and
`enable` is a real render rather than the refusal arm's "".

THE REPAIR CITES RATHER THAN RE-SPELLS. The old pattern was a third authoring of
facts extdeps.sudo.elevation and extdeps.systemd.systemctl already own, which is
why it rotted without anyone touching it (DESIGN section 3). The conjunct is now
two, deriving the program spellings from those authorities and split because they
assert different things: that activation ELEVATES NON-INTERACTIVELY, and that it
reaches systemctl's ENABLE --NOW.

WHY THIS IS NOT measure() == measure(). `enable` and `--now` stay literal, and
they are the discriminating half: they are systemctl's own operands, spelled
inline by the builder rather than read from any row, so a command that carried
the units without the verb still fails here. What the derived halves buy is that
a future re-homing of the sudo or systemctl spelling moves the assertion with the
authority instead of leaving a fourth copy to rot.

Not verified locally: the same stale-binary limit recorded on the previous commit
applies. CI is the authority.

* join is not a std.types export: the two derived patterns build with concat

Preparation refused on the previous head with a single diagnostic --
  runner_host_deploy_witness_test.dag:4:33: name 'join' not found in module
  'std.types'
-- so the import I added to carry the derived invocation patterns named a symbol
that module does not export. The witness already builds every other composed
pattern with concat and needs no import for it; the two new ones now do the same.

This is my own defect from the previous commit, not new fallout: the repair it
carries is unchanged, only its spelling of string concatenation. The stale-binary
limit recorded there is exactly why it reached CI to be caught -- a local compile
under a binary that predates the seal cannot answer questions about this tree.

* Split the 143 runtime-errored enrolments by witness-loader eligibility, and import the 19 the bare closure can never reach

The bare-reference closure that resolves an unimported bare name through the
tree census is switched off for any file declaring an import line
(cli_run build_both_closure_edge_index, source_declares_import_lines). Joined
against the 143 live runtime-errored enrolments, 23 rows sit in files already
past that gate, so no loader-side repair can reach them: 19 are reference rows
whose missing name has exactly one declaring module, and this adds those imports.

No roster row is removed: main refuses at preparation, so no witness has
executed and unenrolling would be the stale-quarantine hazard the roster exists
to surface.

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

* Round 1 measured: unenrol the 8 that now pass, and clear the next frontier name for the 11 that advanced

Required-floor run 32660721426 on this branch: known_red_runtime_errored 143 -> 135,
known_red_now_passing=8. Those eight reported STALE-QUARANTINE — enrolled and PASSED — so
they leave the roster by its own removal path, at exact identity grain, chunk structure
otherwise untouched.

The other eleven repaired rows advanced rather than flipped: their reported missing name
changed, which is the first-failure frontier the floor reports. Round 2 imports the three
successor names in the same three already-importing files.

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

* Round 2 experiment: three import-less files, chosen to discriminate the bare-scan gate

The 120 BARE rows cannot be diagnosed outside the floor: the per-entry loader
resolves the R1 shape and PASSES the witness, the floor's prepared subject already
contains every module, and a whole-tree gunbc run refuses rather than approximating
the floor's subject. So the floor is the instrument and this is a bounded experiment,
not a rollout — three files varying in how many OTHER ambient names lose their
census-derived pull when the file crosses the gate.

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

* Round 2 measured: 24 more unenrolled, and the BARE-file hazard retired by measurement

Required-floor run 32664512304 at 42d0a85: known_red_runtime_errored 135 -> 111,
known_red_now_passing=24, failed=0, planned==executed==terminal==10693.

All 17 rows in the three import-less experiment files flipped to PASS with nothing
else in those files regressing, so the bare-scan gate hazard this lane raised does
not bite for them — measured, not argued. The seven round-1 frontier rows flipped too.
All 24 reported STALE-QUARANTINE and are removed at identity grain: roster 195 -> 171.

Three runtime_axis rows advanced a third time (cost_is_lowerable -> type_decls_anti_unify),
imported here.

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

* Round 3: import the 90 resolvable rows of the remaining 111, in one batch

48 files, 70 imports. Each name has exactly one declaring module the referring file
does not import; three were decided by the consuming field's type rather than by
uniqueness, because the name is corpus-ambiguous and the census resolves that
silently (Dag -> v2.lens.fact_cardinality, SourceFile -> v2.std.artifact x2).

Batched rather than trickled because round 2 retired the bare-scan hazard by
measurement and the fold is the check: every row still executes and a repair that
breaks a sibling shows up as a named failure, not a silent pass.

The 21 rows left are not reference failures — atom_identity_hash arity (12), the
render lexical-shadowing defect, .raw on Int (2), a divergent fixture, and three
runtime_axis rows already imported.

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

* Record why the import is the right fix independent of the roster, and pin each round to its run

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

* Round 3 measured: 111 -> 21, unenrol the 88, and repair the last two reference-shaped rows

Run 32667349586 at 7026838: known_red_now_passing=88, known_red_budget_refused=2,
known_red_runtime_errored=21 — 88+2+21=111, no remainder. failed=0, so the 70-import
batch broke no sibling. Roster 171 -> 83, deletions only.

Two rows moved from runtime-errored to BUDGET-REFUSED at 5001/5003ms against 5000ms.
They stay enrolled: the witness previously threw before doing its work and now runs it,
so this is a real cost debt the repair surfaced, not a regression to absorb.

Repaired here: sigma_families_of_defs (the runtime_axis file's fourth successive
frontier name) and LocalAccelerator, fixed in dag/gunbc/accelerator_demo_plan.dag where
the bare value-position reference is, not in the two witness files that call into it.

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

* Round 4 measured: 21 -> 15, the reference class is drained

Run 32671448306 at eee5a43: known_red_now_passing=7, known_red_runtime_errored=15,
failed=0. Removed: the three runtime_axis rows, the two accelerator_demo rows, and the
two generated_coproduct_exhaustiveness rows whose round-3 budget refusal is now
discharged rather than re-classified. Roster 81 -> 74.

143 -> 15 in four rounds, 127 identities unenrolled, each because a run observed it
passing and it named itself. The 15 left are three non-reference roots: the
Atom.identity type hole (12), the corpus-ambiguous Hit (2), and the eval_call
lexical-tier gap (1).

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 <noreply@anthropic.com>
Co-authored-by: Brian Searls <briansearls1@gmail.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