Skip to content

Make the hand-built argv unwritable at the call site, and land the positive examples that show what to write instead - #8919

Merged
briansrls merged 22 commits into
mainfrom
session/quick-newt-661
Aug 23, 2026
Merged

briansrls merged 22 commits into
mainfrom
session/quick-newt-661

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 22, 2026 •

Copy link
Copy Markdown
Contributor

What lands

extdeps.exec.command ArgvCommand becomes sole_constructor, with one admitted mint (argv_command) caller-sealed by name to typed builders. A hand-spelled word list no longer has a route to a process: the flags of a tool this repository does not own are spelled in that tool's own extdeps module, beside its cited upstream authority, and nowhere else.

This is Lane B's construction half of gunbc.plans.transport_argv_anemia_dissolution, and it follows the pattern extdeps.shell.exec transport_script_seal already set for TransportScript — including its rule that no test declaration is admitted: a witness obtains an ArgvCommand through a production builder, the same way production does.

One PR, every site, seal included. A partial seal is not a weaker seal, it is a dual-authority interval: while the record literal is writable at some sites, the unconverted ones keep teaching the pattern the seal exists to end (DESIGN §3, replacement migrations cut over at the root).

The carrier also splits the program from its arguments

type ArgvCommand sole_constructor {
  program: NonEmptyStr
  arguments: List<String>
}

execve takes the executable and the argument vector as distinct parameters — the reason already recorded at extdeps.shell.exec RunArgv. Two consequences:

  • The empty argv becomes unrepresentable — evidenced, not claimed complete (see below). gunbc.command_runner carried two HeadAbsent => "empty argv: a command with no words names no program to execute" refusal arms. Both are deleted, not relaxed: the state has no constructor. That is a climb from mitigatable to structurally impossible for that one class (§4b).
  • argv_operands is deleted — it re-derived by dropping a head what the type now carries as a field.

The manual receipt test's empty_argv_refuses is deleted with a paragraph standing where it stood. §4b(4) keeps a class's discriminating evidence enrolled when it climbs, but that presumes the probe stays writable; here the wall's whole content is that its input is unconstructible, and re-admitting the empty value to keep testing its refusal would reopen exactly what the climb closed.

The census the deletion performed

58 record constructions on origin/main (the "75" figure counts string occurrences, including -> ArgvCommand { signature lines). All 58 converted. Beyond them the seal surfaced what a grep for the literal could not:

  • 9 hand-spelled argvs that were never record literals — ["mkdir","-p",…] and ["stat","-c","%i","--",…] passed as List<String> parameters, four ["sh","-c",…] argument lists inside observe_capture_line, and three bare read rows in build_cache_endpoint_observe.
  • 4 laundering seams closed — functions taking argv: List<String> and constructing the record on the caller's behalf (bmc_netboot_run_bmc, observe_capture_line, build_cache_host_read, build_cache_host_read_observed) now take ArgvCommand. A List<String> parameter beside a sealed record is a door in the wall.

Where the builders live, and why not here

Not in extdeps.exec.command. A generic hub may define the agnostic shape but may not enumerate concrete products (DESIGN §3, external upstream decomposition), so the six builders that module used to carry are moved out: curl_download_command, mkdir_parents_command, tar_extract_command, make_command, sed_in_place_command, cp_command now live in extdeps.tools.{curl,mkdir,tar,make,sed,gnu_coreutils}. Sealing the record while keeping the product rows in the hub would have made one module the place every tool's flags collect.

New/extended authorities, each with its cited manual: coreutils (cat/cp/rm/printf/true/whoami), stat (%U/%F/%i), hostname, chmod (octal mode as its own name, not a flags parameter), mkdir, tar, make, curl, sed, busybox (httpd, and tftpd-over-udpsvd), nbd, POSIX test, the OpenSSH client utilities (ssh-keygen -y/-l/-F, ssh-keyscan, ssh-add -l), systemctl enable --now (elevation from extdeps.sudo.elevation, not two more literals), git's config --local, and this repository's own claim_executor CLI.

DFS'd before minting, every time, per the constraint I was given: mkdir_parents_argv, chmod_add_executable_argv, stat_owner_user_argv, shape_git_config_local_argv and sudo_elevate already existed and are consumed, not re-coined. Where a call site needed a neighbouring fact (%U beside %u, --local split from git), the existing row was factored rather than duplicated.

Program names are PATH-resolved where the host is unobserved

I first wrote absolute paths into nine new rows on the rule "a bare name declines to say which binary". still-seal-394 corrected that and is right: an absolute path is a claim about an observed filesystem. extdeps.tools.mkdir and extdeps.tools.chmod record theirs because a sudoers NOPASSWD rule names those commands by path — an observation with a consumer. For a BMC, a fleet member or a runner image this repository has never read, /usr/bin/x would trade a vague spelling for a confident false host fact (§5). All nine reverted; the reason is recorded once and cited at each row. No program this PR touches changes which binary runs, with two stated exceptions where the words DO change, both privileged and both toward the existing authority rather than away from it:

  • runner_enable_command_argv spelled sudo bare with no flag; it now takes extdeps.sudo.elevation's /usr/bin/sudo -n — non-interactive, failing instead of blocking on a tty CI does not have. That module mints only the non-interactive form deliberately, and every other privileged leaf already runs that way.
  • runner_host_installer_command_argv's sudo -E likewise becomes the authority's absolute /usr/bin/sudo, keeping -E.

Both are recorded at the builder rather than left for a reader to diff.

Two dependencies and one coverage boundary, stated

  1. dag/extdeps/tools/env.dag (One binary, two spellings: 'env'/'/usr/bin/env' and 'chmod'/'/bin/chmod' are section-3 nicknames at the transport layer #8918, still-seal-394) is MERGED and merged in here. Two sites are env invocations; env_prefixed_command lives on this side, over the sealed mint, because the env authority must not import ArgvCommand or the dependency inverts. Three merge resolutions are recorded in the merge commit: env.dag takes main's wholesale (my branch had accidentally committed the throwaway stub I typechecked against — a git add -A picked up the untracked file; it is gone), the two env call sites take the builder form, and chmod_set_mode_command now takes its program as a parameter because One binary, two spellings: 'env'/'/usr/bin/env' and 'chmod'/'/bin/chmod' are section-3 nicknames at the transport layer #8918 landed chmod's second spelling and the two are two facts — the observed /bin/chmod a sudoers rule names, and the PATH-resolved name for a host nobody has read. fleet_converge_plan_cli keeps the resolved row One binary, two spellings: 'env'/'/usr/bin/env' and 'chmod'/'/bin/chmod' are section-3 nicknames at the transport layer #8918 gave it, so this merge changes no emitted word there.
  2. extdeps.posix.sh_invocation is a new module because of a real cycle, not taste: extdeps.exec.command imports shell_command_language for posix_single_quote, so the invocation builder cannot live there and import the carrier back. The corpus refused with a circular-dependency diagnostic; the split mirrors extdeps.languages.bash.{subject,invocation}.
  3. What the seal does not reach, so coverage is not read as total:
    • It confines WHO constructs, not WHAT flags a sanctioned builder spells. A builder omitting curl's --fail is still writable inside its own module — which is why each builder is homed beside its cited authority rather than the seal being treated as the guarantee.
    • transport shell { argv: [...] } operation declarations are a separate population that NO citation-based conversion can reach today — blocked by A transport argv identifier is never name-resolved: zero diagnostics, silently wrong argv #8916 (gap-analysis row 29), not left as this lane's residue. The mechanism, measured by still-seal-394 and relayed rather than re-measured by me: a symbol declared nowhere in the corpus, placed in a transport argv, produces zero diagnostics, against a same-file same-run control where the identical name in an ordinary fn body reds undefined variable. Reading the emitted AST shows the position parses expressions (ExprVar, ExprCall) and simply never resolves them, so a citation written there emits as a literal token and nothing refuses — silently wrong argv, below floor, with a structurally-guaranteed ceiling since it is missing wiring over the same Node-tree read the namespace authority already performs everywhere else. What I measured myself: all 58 sites in this PR's population are .dag record constructions in fn/func bodies, so the seal's coverage claim and that defect do not overlap. Converting the transport-argv population is unblocked by A transport argv identifier is never name-resolved: zero diagnostics, silently wrong argv #8916 landing, not by more work in this lane.
    • posix_sh_program_command / bash_program_command are the declared residual: a script body is one argument to one program, not an argv. 11 sh -c call sites (10 production fleet observation/enrollment probes using $(...), &&, ||, plus one manual receipt test needing a program that exits nonzero printing nothing) and 1 bash -c. Their dissolution is the shell → dag lane's, and both rows say so — a caller reaching for them to run one program with flags is spelling an argv inside a string, and review must refuse that exactly as it refuses the record literal.

Verification

The wall was proven by execution, not by its type declaration. Running claim_executor --required-floor against an early revision of this branch, argv_command REFUSED a real caller and named it:

dag/extdeps/git/git.dag:553:3: error: constructor call admission refused:
  'extdeps.exec.command.argv_command' refuses call from
  'extdeps.git.git_config_local_set_command' — permitted callers: [...]

Three times, on three different omissions of mine — that one, plus readlink_command and the findutils fd-walk builder, both caught by a later run. Each refusal was a genuine defect in my admit list — the module is extdeps.git, not extdeps.git.git — and it is the discriminating evidence that the admission is live rather than decorative: an inert admit_callers would have compiled the same file silently. (extdeps.shell.exec transport_script_seal records an inert-admit_callers finding from #8593; this one fires.)

The climb rests on a refinement, so the refinement was measured

program: NonEmptyStr makes the empty argv unwritable only if String where non_empty is enforced at construction — a type name is not safety (§4b). Measured on a gunbc built from this branch, one discriminating pair, same file and same mechanism with only the literal changed:

declaration result
data probe: NonEmptyStr = "" refused — type mismatch: expected 'Product(NonEmptyStr)', got 'Primitive(String)'
data probe: NonEmptyStr = "mkdir" accepted; the module resolved and its function evaluated

"" as NonEmptyStr at a call site refuses identically, so neither construction route admits an empty program. Boundary: this is the source→.dag acceptance path only; §4b makes rung per-path, and the Rust emission path is untested here.

Why it is not enrolled as a witness: the only in-corpus vehicle for asserting a refusal is compile_dag_diagnostic_census over a virtual module, which reads the live tree — and a ReadsLiveTree file is declined by the floor before the fold, so enrolling it would add an inert witness. Inert evidence reads as coverage and is worse than none, so the command and both outputs are recorded in the paragraph where the deleted test stood. (Two files in the corpus do execute such a census by declaring SubstrateInputsOnly; gunbc.compile_diagnostic_census's own note already adjudicated that pairing as a mis-declaration, so becoming the third specimen was refused rather than overlooked.)

What this PR claims about the empty-program climb, as four facts rather than one

Collapsing these is how a climb gets reported finished while its evidence has no route, so they are stated separately:

  1. The empty argv has no representation in the carrier — the two deleted refusal arms are unreachable.
  2. The refinement that rests on is evidenced by a recorded execution — the pair above.
  3. That pair is not required-floor enrolled, and cannot be today.
  4. The Rust emission path is unmeasured — nothing here says what an emitted mirror's constructor admits (the same gap DESIGN records for extdeps.uri UriValidatedScalar).

So this PR claims the class as evidenced but not floor-enrolled on the source path, and unmeasured on the emission path — not a completed climb. Under the strict §4b rule, a completed climb retains executing evidence, and this one has a receipt. The arms stay deleted because fact 1 holds regardless of enrolment: what the enrolment gap withholds is the claim, not the deletion.

None of the seal's own result depends on this. The 58 conversions, the nine non-record argvs, the four laundering functions and the three unplanned refusals stand independently of the empty-program class.

Also confirmed by refusal during this work: // annotations placed inside a declaration body are rejected at module-item grain (DESIGN §4c), and the circular-dependency diagnostic named in point 2 above.

Local floor status, stated as it is. --required-floor reaches strict-preparation in this container and reports located errors; across four runs I drove my population from 2615 cascading diagnostics (a missing import in the hub) to the four listed below, each fixed. The final confirming run was killed by memory pressure inside strict-preparation with no errors emitted, and a zero from a dead run is not a pass — so I am NOT claiming a green local floor. What I am claiming is that every diagnostic this instrument attributed to files this branch touches was read and fixed:

  • the missing-import cascade (hub importing an unmerged module),
  • the extdeps.posix.shell_command_language ↔ extdeps.exec.command cycle,
  • eight build_cache_host_read call-shape mismatches (the parameter changed from argv to command),
  • the git admit-list module path, and five in-body annotations.

Four diagnostics remain in files this branch does not touch (extdeps.git.object_store ×2, src/v2/std/collection.dag, v2.workflow.floor_preparation — map_get returning Outcome matched against Present/Absent). I did not establish whether they are pre-existing on main or newly surfaced, so they are flagged rather than attributed.

CI on this branch is the real instrument and cannot go green until #8918 lands;

gunbc-ci-auto-heal and others added 12 commits August 22, 2026 17:13
…uilders that show what to write instead

extdeps.exec.command ArgvCommand becomes sole_constructor with one admitted
mint (argv_command), caller-sealed by name to typed builders homed in each
tool's own extdeps module beside its cited upstream authority. All 58 record
constructions on main are converted in this change, because a partial seal is
a dual-authority interval rather than a weaker seal (DESIGN section 3).

The carrier splits program from arguments, which makes the empty argv
unrepresentable and dissolves two runtime refusal arms in gunbc.command_runner
(DESIGN section 4b: structurally impossible over mechanically preventable).

The seal surfaced nine hand-spelled argvs that were never record literals and
four List<String> laundering seams; all are converted or closed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DhAfyPkuxnjZaTzPn5PyE1
…e line per row

still-seal-394's correction: the rule is not 'PATH-resolved is the safe
default'. An absolute path is a claim that this repository observed the
target's filesystem, and it is the STRONGER form wherever that claim is true --
a sudoers rule can name it and a preflight can test for it. PATH resolution is
correct only where the host is unobserved.

The reasoning, the climb criterion and the roadmap_dashboard_instance_apply
counter-example live once at extdeps.exec.command
program_spelling_is_an_observation_claim; the ten rows it governs carry one
line pointing at it instead of ten copies of the paragraph.

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

The refusal census does not stop at the record literal. build_cache_endpoint_observe
still spelled four argvs as bare word lists (two cat, one stat -c %U, one
readlink) and host_effect_realize spelled the /proc fd walk as a fifth; all five
now derive from cited authorities, with find's -lname glob fact homed in a new
extdeps.tools.findutils beside the flags rather than in the caller that met it.

stat's name row gains the -- end-of-options guard its sibling rows already
carried: one module was answering one question two ways, and these operands come
from observed host state, which is exactly where a leading-dash path appears.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DhAfyPkuxnjZaTzPn5PyE1
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DhAfyPkuxnjZaTzPn5PyE1
…ement the climb rests on

The seal refused readlink_command and the findutils fd-walk builder -- two
admit-list omissions of mine, caught by execution rather than by review.

The empty-argv climb claims program: NonEmptyStr makes an empty program
unwritable. NonEmptyStr is a refinement, not a mint, so that claim is only as
good as its enforcement at construction. Measured with a discriminating pair on
a freshly built gunbc: data p: NonEmptyStr = "" is REFUSED at the declaration,
data p: NonEmptyStr = "mkdir" is accepted and evaluates. Recorded beside the
deleted test, with the path boundary and the reason it is not enrolled.

Two NonEmptyStr literals become data rows, because a cast of a String literal
at a call site is refused by the same judgment.

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

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DhAfyPkuxnjZaTzPn5PyE1
…lane's residue

Preliminary ruling relayed from the shell -> dag lane: an identifier in a
transport argv position is never name-resolved, so no citation-based conversion
of those sites is possible by any author until gunbc#8916 closes. Naming it as
residue would read as a conversion that stopped short and would put the
obligation on the wrong lane.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DhAfyPkuxnjZaTzPn5PyE1
Operator ruling relayed: a completed climb retains executing evidence, and this
one has a recorded receipt with no enrolled route. The arms stay deleted -- the
empty argv is unrepresentable regardless of enrolment -- but the claim is
evidenced-but-not-floor-enrolled on the source path and unmeasured on the
emission path, stated as separate facts so they cannot collapse into 'done'.

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

Resolutions:
- extdeps/tools/env.dag takes main's wholesale. My branch had accidentally
  committed the throwaway stub I was typechecking against (a git add -A picked
  up the untracked file); it is gone, and the authority is still-seal-394's.
- The two env call sites take my builder form. main converted the 'env' program
  WORD at both; env_prefixed_command carries the whole invocation, so the
  binding is a modeled EnvSet rather than a joined string and the word comes
  from the same row either way.
- chmod_set_mode_command now takes its program as a parameter, because main
  landed chmod's second spelling and the two are two facts: the observed
  /bin/chmod a sudoers rule names, and the PATH-resolved name for a host we
  have not read. fleet_converge_plan_cli keeps the resolved row main gave it,
  so this merge changes no emitted word there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DhAfyPkuxnjZaTzPn5PyE1
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 22, 2026 19:07
@gunbai-bot

gunbai-bot Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

The approving review reads this as a clean climb to structurally-impossible. This PR does not claim that, and the difference is deliberate rather than modesty — flagging it here so nobody later cites the approval as having established the stronger claim.

What the PR body claims, as four separate facts:

  1. the empty argv has no representation in the carrier — the two deleted refusal arms are unreachable;
  2. the refinement that rests on is evidenced by a recorded execution (data p: NonEmptyStr = "" refused, = "mkdir" accepted, same file, one literal changed);
  3. that pair is not required-floor enrolled, and cannot be today — the only in-corpus vehicle for asserting a refusal reads the live tree, and a ReadsLiveTree file is declined by the floor before the fold, so enrolling it would add an inert witness;
  4. the Rust emission path is unmeasured — the same gap DESIGN records for extdeps.uri UriValidatedScalar.

Under the strict §4b rule this repository applies, a completed climb retains executing evidence; this one has a receipt. So the honest label is evidenced but not floor-enrolled on the source path. The arms stay deleted because fact 1 holds regardless of enrolment — what the enrolment gap withholds is the claim, not the deletion.

Everything else in the review I agree with, and one part of it is genuinely useful corroboration rather than restatement: an independent check that every admit_callers entry resolves to a real declaration. That wall refused three of my own callers by name during this work (a wrong module path, readlink_command, and the findutils fd-walk builder), which is the evidence it is not inert — extdeps.shell.exec transport_script_seal records the opposite outcome for a seal that compiled a bad caller in silence.

— sent from quick-newt-661

gunbc-ci-auto-heal and others added 6 commits August 22, 2026 19:42
socket_inode_holder_argv became socket_inode_holder_command when the /proc fd
walk stopped being a hand-spelled argv, and this witness -- the control that
pins the ? wildcards against the bracketed glob that silently matches nothing --
still called the old name. CI caught it; I had not.

It asserts exactly what it asserted before: the emitted pattern is
socket:?3894042? and contains no brackets. Only the route to the words changed,
from a List<String> return to argv_words over the ArgvCommand.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DhAfyPkuxnjZaTzPn5PyE1
… this branch was in review

TWO CONFLICTS, AND ONE OF THEM IS THE SEAL DOING ITS JOB.

extdeps.tools.gnu_coreutils -- textual. main (#8930) deleted the
`gnu_coreutils_diff_flags_dissolve_on` row and its `std.dissolution` import,
replacing the row with a leading annotation on `grep_recursive_numbered_flags`
that says why a `diff` flags literal must not come back. This branch had added
argv builders and widened the `std.types` import in the same two regions. Took
main's deletion whole -- the row and the import are gone -- and kept this
branch's builders and its `{ NonEmptyStr, String, List, FilePath }` import,
which is the union both sides need. Nothing in the tree still references the
deleted row.

gunbc.fabric_witness_run -- SEMANTIC, and git merged it cleanly, which is
exactly why it needed reading rather than trusting. main added
`cited_symbol_run_command`, a NEW hand-built `ArgvCommand { argv: [...] }`
record literal with the binary path and mode flag spelled inline, landed while
this branch was in review. That construction does not exist any more: this
branch splits the carrier into `program` / `arguments` and seals it behind the
`argv_command` mint. Auto-merge produced a file that would refuse.

Converted it the same way as the other 58, and to the builder this branch
introduced for precisely this shape -- `claim_executor_command(mode_flag:,
operands:)` from `gunbc.claim_executor_cli`, which already owns "where the
release binary lives" for `floor_run_command` two functions below it. The
inline `"target/release/claim_executor"` is gone with it, so the path is one
fact again rather than two that agree. No admit-list change: the caller reaches
`argv_command` through `claim_executor_command`, which is already admitted.

That is the deletion-as-census working across a merge rather than within one
diff -- a new construction of a removed shape cannot arrive quietly, because the
constructor it needs is gone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DhAfyPkuxnjZaTzPn5PyE1
…ive, not competing

ONE CONFLICT, IN gnu_coreutils, AND BOTH SIDES ARE KEPT WHOLE. main (#8845)
added the install(1) rows -- flag data, `coreutils_install_*_argv` builders,
and a renamed `coreutils_rm_force_recursive_*` pair -- in the same region where
this branch added its `ArgvCommand` builders, and widened the same `std.types`
import to the same set in a different order. Nothing was in tension: the merge
is both sets of declarations, with main's import spelling taken so this file
differs from main only by what this branch adds.

VERIFIED BY DECLARATION SET, NOT BY READING THE HUNK. Diffed the resolved
file's `fn`/`data` names against both parents: nothing main had is missing,
and nothing this branch had is missing except `rm_force_recursive_flags`, which
main DELETED in favour of its own `coreutils_rm_force_recursive_flags`. Dropping
it is main's decision, not a merge casualty, and no reference to the old name
survives anywhere in the corpus.

The textual conflict also swallowed `readlink_command`'s closing brace, because
the shared trailing `}` was the one line both sides had in common. Braces now
balance 20/20; a hunk that reads correctly is not the check.

NO 60th HAND-BUILT ARGV THIS TIME, and I looked rather than assumed after the
last merge produced one. main's new `argv:` occurrences are named parameters to
`shell_privileged_command_text_of_argv` and `transport shell` declarations --
`List<String>` positions, not `ArgvCommand` record literals -- so the seal has
nothing to refuse. Grep for a record literal outside the mint returns empty.

Worth naming for the lane rather than for this diff: `coreutils_install_*_argv`
and its `argv: List<String>` consumer are the same anemic shape this branch
closed four of, in a different carrier (privileged shell text). They arrived
after the census and are outside the sealed population; converting them is
follow-up work, not merge work.

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

THE MERGE PRODUCED A COLLISION NEITHER SIDE COULD SEE ALONE. main's #8845
added `gunbc.live_deploy.operations.rm_force_command(paths: List<String>) ->
String` -- privileged shell TEXT for removing several paths. This branch added
`extdeps.tools.gnu_coreutils.rm_force_command(path: String) -> ArgvCommand` --
the cited tool operation for one path. Different layers, different carriers,
different arity, same spelling. Each was unambiguous in its own tree.

THE COMPILER REFUSED RATHER THAN PICKING, which is the outcome worth recording:

  dag/gunbc/live_deploy/emit.dag:818:29: error: ambiguous reference
  'rm_force_command': 2 candidates: extdeps.tools.gnu_coreutils.rm_force_command,
  gunbc.live_deploy.operations.rm_force_command — qualify by containment path,
  alias, or rename

Ten references, six in `live_deploy/emit.dag` and four in its test. All ten
want the shell-text one -- they pass `paths:` and feed `deploy_raw` -- so they
are now spelled `gunbc.live_deploy.operations.rm_force_command`. Qualification
is the diagnostic's own first suggestion and the least invasive of the three:
it edits references, not authorities, and renames nobody's landed symbol.

NEITHER NAME IS WRONG, which is why this is not a §3 nicknaming repair. §3
forbids two names for one concept; this is one name for two concepts, and both
are honest in their own module -- `extdeps/` keeps the tool's real operation
name, and the product layer names the privileged-text form it owns. If either
should move it is a question for the live-deploy lane, not something to settle
inside a merge.

ONE LATENT INSTANCE LEFT DELIBERATELY, named rather than silently passed over:
`dag/gunbc/build_cache_endpoint_path.dag:130` calls the unqualified
`rm_force_command(path:)` and did NOT error, because
`gunbc.live_deploy.operations` is not in that module's import closure. It is
correct today and one import edge away from the same refusal -- the same
closure-scoped resolution class this session filed as gap-analysis row 30
(gunbc#8943) and repaired four sites of in gunbc#8944. Left unqualified because
this PR is otherwise complete and a speculative edit buys a 40-minute CI cycle;
recorded here so the next reader finds it by search rather than by breakage.

Regen passed on this head (first_generation_equal=true), so the inherited
#8691 red is gone and this floor refusal was the only remaining failure.

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

gunbai-bot Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor Author

gunbc-ci-auto-heal and others added 2 commits August 23, 2026 06:38
…d admit row

THE MERGE closes the last inherited red. #8989 hoisted the §4c-illegal
annotation out of `witness_retired_runner_slot_owner_refuses`'s match body;
while it stood, floor preparation died before planning a single witness, so
every "failing" floor verdict recorded anywhere in the repository during that
window was uninformative rather than negative. This branch's own runs in that
window say nothing about this branch.

THE NIT, from review 54984 and held deliberately until now: one `decl_ref` row
in `argv_command`'s `admit_callers` list sat at 8 spaces where its 39 siblings
sat at 4. Now 40 of 40 at 4. It is cosmetic, which is exactly why it waited —
pushing it alone would have cancelled an in-flight run, dropped five approvals
(scored per head), and spent a ~45-minute CI cycle in a fleet completing about
one run in six, all to correct four spaces. Riding the merge costs nothing.

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

gunbai-bot Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor Author

… one of them was the witness's fault

THE FLOOR RAN FOR THE FIRST TIME ON THIS BRANCH and reported failed=10 against
main's failed=8 on the same head (13db52a, run 32621117917). The two extra
are mine. They are opposite defects and the difference is the whole entry.

BUSYBOX -- MY CODE WAS WRONG, THE WITNESS WAS RIGHT.
`busybox_build_is_modeled_and_grounded` asserts `'mkdir' '-p'` and got
`/usr/bin/mkdir`, because this migration routed the call through
`mkdir_parents_command`, whose wrapper cites the recorded absolute path.
`gunbc.busybox_bmc_build` runs its whole sequence under `LocalExec` on whichever
machine the operator invoked the cross-build from -- it demands an
`arm-linux-gnueabi-` toolchain, not a host this repository has ever read. So the
absolute path was a claim about an unobserved filesystem: the exact §5
fabrication `extdeps.tools.mkdir`'s own rows warn against, committed by me while
quoting the rule. Now routed through `mkdir_parents_command_at` with
`mkdir_path_resolved_program`, with the reason stated at the call site as that
module asks its PATH-resolved callers to do.

The mkdir note is corrected in the same commit rather than left standing: it
said the BMC applet was the one such caller and "every other caller gets the
recorded absolute path". That became false the moment this second caller landed,
and a note asserting a population it no longer has is the stale-recital class
DESIGN §3 exists to stop.

SUDO -- MY CODE WAS RIGHT, THE WITNESS PINNED THE OLD SPELLING.
`srv4_runner_installer_command_cites_installer_with_env` asserts
`'sudo' '-E' 'bash' ...` and now renders `/usr/bin/sudo`. That change is
deliberate: sudoers matches on the absolute path, so a PATH-resolved spelling
would let the caller's own PATH decide which binary crosses the privilege
boundary, and `sudo_elevate` two functions above already used this row -- the
alternative was two spellings of one binary in one module. The assertion is
updated to the new words.

THE ASYMMETRY IS THE POINT. Same migration, same kind of diff, two witnesses
red, and the correct repair ran in opposite directions -- one edits the code,
one edits the oracle. Deciding by which side is easier to change would have got
one of them backwards; deciding by whether the host was OBSERVED gets both right.

Also lands the annotation I owed at `sudo_binary_path` (review 55022): the -E
row documented its own `-n` delta while the path delta was left implicit. Both
are now stated at their rows.

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

gunbai-bot Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor Author

@briansrls
briansrls merged commit 0550154 into main Aug 23, 2026
1 check passed
@briansrls
briansrls deleted the session/quick-newt-661 branch August 23, 2026 14:42
gunbai-bot Bot pushed a commit that referenced this pull request Aug 23, 2026
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.
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 pushed a commit that referenced this pull request Aug 23, 2026
… that closes the class (#9045)

#8919 replaced a hand-built argv at command_runner.dag stat_owner_name_capture with
extdeps.tools.stat stat_owner_user_name_command and did not add the import. main
refuses at strict preparation:

  function 'stat_owner_user_name_command' not found in scope
  (dag/gunbc/command_runner.dag:268)

This is the same class #9031 repaired -- a seal and its construction sites landing
in separate PRs -- and it is the second of two #8919 stranded. The call site is
correct and is exactly what the seal wants, so this changes the import list only.

THE CLASS IS CLOSED AT TWO, measured rather than hoped. Enumerated all 24
`*_command` builders defined under extdeps/tools/ and extdeps/posix/, then checked
every gunbc module that calls one for a matching import, a qualified spelling, or a
local definition. Exactly one unresolved instance -- this one. There is no third.

RED before, green after, on the same probe: a clean origin/main checkout produces
the diagnostic above; with the import the same entry compiles with 0 blocking
diagnostics and 52 source-annotation diagnostics, which are identical on main and
predate this change.

Co-authored-by: Brian Searls <briansearls1@gmail.com>
briansrls added a commit that referenced this pull request Aug 23, 2026
…(carrier-exactness recut) (#8990)

* Split the encode refusal domain out of the decode one, so the load classifier
cannot name a state the loader cannot produce

Recut item 1 of 7. This is a correctness fix, not carrier tidying.

THE DEFECT. ClosureDocIncompleteWithoutAdmission is produced by
encode_closure_document_checked and by nothing else -- no decode path reaches
it. It nevertheless sat in ClosureDocRefusal, which closure_document_load_standing
matches EXHAUSTIVELY. So the load classifier was obliged to assign a standing
to a state loading cannot produce, and it answered LoadDocumentMalformed --
which standing_may_supersede_generation makes the ONE standing permitted to
supersede a newer document. An encode-only state had a route to "may
overwrite".

This is a closed match over a dishonest domain: exhaustiveness is satisfied,
the compiler is content, and the arm answers for something that cannot occur.
Nothing was miswritten; the TYPE was wider than the operation's domain.

THE FIX is not a new guard. ClosureDocEncodeRefusal now carries that arm and
ClosureDocEncodeOutcome refers to it, so the classifier's parameter can no
longer express the cause. The question stops being answerable rather than
being answered correctly -- DESIGN section 4b's top rung, unrepresentable
rather than validated.

EVIDENCE, and the control is the half that makes it evidence. A temporary
paired probe, both files staged so they reached the remote runner:

  probe   closure_document_load_standing(cause: ClosureDocIncompleteWithoutAdmission{..})
          -> error: type mismatch: expected 'Coproduct(ClosureDocRefusal)',
             got 'Coproduct(ClosureDocEncodeRefusal)'

  control closure_document_load_standing(cause: ClosureDocNotAnObject)
          -> typechecks PAST the same call; fails only at the ProcessExit
             boundary, which is the host's return-type rule, not a typecheck

Without the control the probe's failure would have been satisfied by any
breakage at all -- a typo, a bad import, a wrong module name. The control
proves the module loaded, the imports resolved and the call typechecked, so
what the probe refuses is the domain split and nothing else. Both probe files
are deleted in this commit: they declare no test fn and must never enrol,
since a file designed to fail compilation would red the floor for everyone.

Runtime suites green after the split: commit_closure_witness_main exit=0,
load_standing_witness_main exit=0.

ONE CONSEQUENCE STATED RATHER THAN HIDDEN. cause_is_incomplete_without_admission
is now total by construction -- ClosureDocEncodeRefusal has one arm, so the
match can only answer true, and by this stack's own standard that is a
decoration. It is kept, because it is the correct residue of a climb: the
check did not get stronger, it became unnecessary, and section 4b(4) keeps the
evidence enrolled while the obsoleted discrimination goes. What replaced it is
a compile-time property no Bool-returning witness can express, which is why
the probe above is recorded here rather than enrolled as a claim.

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

* Bind the partial-closure admission to its subject, so a token for A cannot
authorize encoding B

Recut item 7, and the one the design thread called the highest-priority
correction. This closes the authority-substitution hole #8965 declared as
honest rung debt rather than fixed.

THE DEFECT. PartialClosureAdmission { reason } carried no subject. The encoder
took a closure PLUS an optional admission and checked only that one was
PRESENT:

    admit closure A -> token T
    encode closure B with T -> ACCEPTED

sole_constructor did not prevent it: .dag has no module privacy, so it blocks
the record literal while the public mint stays freely callable. Nor could the
existing mutation have caught it -- deleting the check proves the check is
READ, which a bearer token satisfies perfectly. That is why this sat at
mitigatable with the rung declared instead of claimed.

THE REPAIR IS A SHAPE, NOT A CHECK. AdmittedPartialCommitClosure holds the
closure it admits, and encode_admitted_partial_closure_document takes ONLY
that carrier. There is no second closure to disagree with it, so "a token for
A used on B" is not refused at runtime -- it has no spelling. The partial
encode entry performs no validation because nothing is left to validate.

`unresolved` is DERIVED at the mint from the closure it is given. A
caller-supplied population would reintroduce the same substitution one field
down: an admission truthfully about A, carrying B's missing objects.

DISCRIMINATOR, and it had to be re-derived rather than copied. The thread
specified "admission for A used with B -> refuses or cannot be constructed",
but after the reshape the mismatch CANNOT BE PASSED -- one parameter, closure
is a field -- so a probe passing a second closure would only be an arity
error. The single remaining forgery route is hand-assembling the carrier:

  probe  AdmittedPartialCommitClosure { closure: <never minted>, .. }
         -> error: sole_constructor type 'AdmittedPartialCommitClosure'
            cannot be constructed outside its defining module   (exit 1)

TWO CLAIMS ADDED, both executing:
  an_admission_names_the_objects_it_admits_as_missing -- the population is the
    closure's own, not a caller's assertion
  the_mint_refuses_a_complete_closure -- admitting a partial write for
    something with nothing missing is a category error, and this is what keeps
    the mint honest about deriving rather than trusting

Suites: commit_closure_witness_main exit=0 (12 claims),
load_standing_witness_main exit=0 (6 claims).

THREE DEVIATIONS FROM THE PROPOSED SHAPE, each deliberate.

NO NonEmptyList. The corpus has none, and minting one for a single field would
grow net concepts to buy a guarantee the mint's refusal already provides. So
the SUBJECT BINDING is structural while the emptiness exclusion stays
mitigatable -- `unresolved: List` can represent an empty admitted population
even though this mint cannot produce one. Next-rung trigger: a NonEmptyList
authority earning its place from more than one consumer.

NO one-member refusal coproduct. `type X = OnlyArm` does not declare a nullary
variant, it reads as a type alias and fails to resolve. The refusal is an arm
of PartialClosureAdmissionOutcome instead; a second genuine refusal joins that
coproduct and every match fails to compile at the match, which is what the
nesting was for.

TWO ENCODE ENTRIES rather than one with an optional token:
encode_complete_closure_document refuses anything uncontained;
encode_admitted_partial_closure_document is total because the mint settled it.

COVERAGE OWED, NOT CLAIMED. scm_commit_closure_json_v2_witness_test.dag has no
ProcessExit driver, so the three call sites retargeted there are typechecked
but NOT executed. The floor is the only thing that runs them and it is
currently refusing for an inherited reason, so that execution is owed once
main reopens.

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

* Narrow the repository encode refusal to the one cause encoding can produce,
and give that arm its first witness

Recut item 6. Same dishonest-domain class as item 1, one layer up.

THE DEFECT. RepositoryEncodeClosureDocRefusal wrapped the WHOLE
ClosureDocRefusal decode population -- fifteen causes -- while
encode_repository_checked produces exactly ONE of them
(ClosureDocEdgeTargetUnresolved) from exactly one place. A consumer matching
this arm had to handle format-tag and unknown-connective causes that no encode
path can raise, and a reader could not tell from the type which were real. The
type answered for a domain it does not own.

It also round-tripped an identity through text: the arm carried a rendered
key while its two sibling arms carry ObjectId directly. An identity left as a
string is one nobody can resolve back.

Both are fixed by RepositoryEncodeUncontainedTarget { target: ObjectId }, with
first_uncontained_target returning the domain type instead of a key.

THE ARM HAD NO WITNESS, AND THE GREEN SUITE IS HOW I ALMOST MISSED IT. All
three suites passed after the change. But the encode-cause helper enumerates
three tags and the claims asserted only two -- "commit_root" and
"checked_out". Nothing drove "uncontained_target". The arm was REACHABLE (a
grafted store whose root's children were never copied produces it) and merely
unoccupied, so changing its payload type would have compiled green with
nothing establishing that the identity survives. Reachable-and-empty is a
quiet guard, not a dead one: the answer is to occupy it.

scm_env_an_uncontained_target_refuses_to_encode_and_names_it now drives it,
and asserts TWO things on purpose. The tag alone would pass whether the arm
carried a resolvable ObjectId or a stringified one, so it also checks the
CARRIED target against the store's own uncontained population -- which is the
property the type change was for.

Both halves measured rather than argued:

  24 claims, membership vs the grafted store    exit=0
  membership vs the COMPLETE store (empty set)  exit=1

The second is what proves the identity check is not vacuous. I could have
reasoned that a fold over an empty list returns false; that is the
substitution this stack keeps catching, so it was run instead.

A DIRECT DRIVER IS ADDED TO THIS WITNESS, and it is scaffold with a stated
end. The floor discovers `test fn` itself and never calls it; it exists
because the floor is currently refusing before subject preparation for a
reason this branch does not own, and these 24 claims otherwise had NO
execution path -- this module's change would have been typechecked and never
run. `gunbc run --function` cannot drive a Bool-returning `test fn`. Delete it
once the floor executes these identities again; the comment on it says so.

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

* Say only what the evidence establishes: an uncontained target, not the first

Two corrections from design review of the item-6 landing. Both are the class
this stack keeps producing -- a name or a tool promising more than anything
verifies -- so they are fixed rather than argued.

(1) THE HELPERS PROMISED AN ORDERING NOTHING CHECKS.
first_uncontained_target and first_uncontained_key say FIRST. The witness
establishes MEMBERSHIP: the carried target belongs to the store's uncontained
population. With a single uncontained object every member is also the first,
so the observation cannot distinguish "actually first" from "some legitimate
member" -- the name was the stronger claim and it had no discriminator.

Renamed to an_uncontained_target / an_uncontained_key. The refusal needs one
ACTIONABLE EXAMPLE and no consumer depends on which; that is the real
contract, so the name now states it.

Deliberately NOT fixed by adding a two-target ordering fixture. Order is not
an interface fact here, and pinning it would freeze an incidental traversal
order that a later keyed or canonical representation of uncontained_targets
should not have to preserve. This is the opposite decision from
two_uncontained_children_are_named_in_order, where the reverse IS load-bearing
because positions are the encoding -- the difference is whether anything
downstream depends on the order, not whether an order exists.

(2) THE DRIVER'S OWN COVERAGE WAS UNGUARDED. A hand-sequenced ProcessExit
driver that omits a claim turns "driver green" into a subset run that reads as
a full pass -- the nothing-ran-versus-nothing-failed trap, inside the tool
added to avoid it. The invariant is that every declared `test fn` appears
exactly once in its driver. Measured:

  scm_commit_closure_witness_test      declared=13 dispatched=13
  scm_load_standing_witness_test       declared=6  dispatched=6
  scm_repository_envelope_witness_test declared=24 dispatched=24

And the check discriminates -- planting a claim with no driver entry gives
declared=7 dispatched=6 -- verified rather than assumed.

NO GATE WAS COMMITTED FOR IT, and that is a decision rather than an omission.
Durable enforcement machinery for an artifact with a scheduled deletion is
scaffold protecting scaffold; the real dissolution is the floor executing
these identities, which removes the driver and the invariant together. The
rung is recorded on the driver as MITIGATABLE, enforced by hand.

Suites after both changes: envelope_witness_main exit=0 (24),
commit_closure_witness_main exit=0 (13), load_standing_witness_main exit=0 (6).

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

* Correct the driver's coverage invariant: an identity set, not a count

The invariant recorded on the repository witness driver was declared ==
dispatched. That is the weaker check it sounds like, and recording it as the
guarantee made this comment the fourth instance in this stack of prose
asserting a wall stronger than the mechanism behind it -- this time inside the
artifact added to prevent exactly that failure.

WHAT CARDINALITY CANNOT SEE:

    declared    A B C D
    dispatched  A B C C

Both populations are four and D never executes. Demonstrated rather than
argued, by duplicating one dispatch and dropping another on a sibling witness:

    count check  declared=6 dispatched=6   -> PASS
    reality      an_honest_collision_is_its_own_standing_and_never_supersedes
                 never ran

The invariant is now exact SET EQUALITY of declared `test fn` names against
dispatched reason strings, plus uniqueness in both populations. Measured
across every witness carrying a driver:

    scm_commit_closure_witness_test       13 identities, sets equal, no dups
    scm_load_standing_witness_test         6 identities, sets equal, no dups
    scm_repository_envelope_witness_test  24 identities, sets equal, no dups

and falsified by the planted case above, which the previous check passed.

NO GATE IS COMMITTED, unchanged from before and for the same reason: durable
enforcement machinery for an artifact with a scheduled deletion is scaffold
protecting scaffold. The driver's dissolution trigger stands -- the required
floor executing these identities removes the driver and the invariant
together. What changed is only that the recorded invariant now matches the
check that was actually run.

Design review also resolved the fork left open in the previous commit, against
the premise I offered: targeted mutation runs DO stay valuable after the floor
returns, but the answer is to generate an ephemeral driver from the current
roster at mutation time, not to keep a hand-maintained one. Two durable
rosters -- floor discovery and ProcessExit dispatch -- would be two authorities
for which claims belong to a witness, and the drift is predictable (a new test
never dispatched, a renamed test leaving a stale entry). That changes nothing
in the tree today; it settles what happens to this driver later.

envelope_witness_main exit=0 (24 claims) after the edit.

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

* v1 inference: generic instantiation must reach record-literal field expectations (>=2 seams) — plus the adjacent below-floor fail-open where a generic field admits the wrong type silently (#8922)

* A generic record literal admits the wrong field type silently at six seams: locate the fail-open, and record two repairs that do NOT close it

DESIGN 4b names "values inhabit declared types" as the ordinary compiler floor.
A record literal of a GENERIC type does not hold it: measured on eleven
single-module probe roots, a wrongly-typed field value is accepted AND EMITTED
at six positions -- fn return, let annotation, record field, list element,
direct-call argument, and a module-scope data annotation -- while the
non-generic control refuses with a located mismatch and the conforming generic
control compiles clean.

The field PRESENCE axis is unaffected (a generic literal missing a required
field still refuses), which rules out "generic declarations are not processed"
and confines the class to the field TYPE axis.

Mechanism, by execution rather than by reading: the instantiation does reach the
literal and the substitution is keyed correctly on "T", but the declaration's
field type node carries no name to key on, so the parameter is never
substituted and the expectation reaching the judgment is a NAMELESS node --
whereupon kernel_value_declared_type_mismatch returns false on formal_name == "".
A second, independent fail-open sits beside it: the substitution value is read
with resolved_type, whose Absent arm is the equally nameless error_type.

Two repairs were built and run against the full arm table and moved NOTHING;
both are recorded because they are the cost of the next attempt. What is still
open is where the type-parameter reference loses its name, which is a modelling
question in a stage DESIGN names load-bearing -- so no code changes here, and
the probe states the exact next question rather than leaving it to be
re-derived.

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

* Correct the mechanism: substitution is innocent, the class is any type declared WITH PARAMETERS, and the paired nonzero makes every zero a reading

The first revision of this probe named the type-parameter reference losing its
name as the cause. Two no-build discriminators falsify that, and a knowingly
stale mechanism claim in a finding other lanes plan against is premise
contamination -- so the doc is rewritten in one pass rather than annotated.

WHAT CHANGED. A generic declaration whose parameter is UNUSED and whose field is
a plain kernel type still fails open, so the trigger is that the declaration
carries type parameters at all, not that a field mentions one. And forcing the
instantiation to bail out with a wrong arity brings the field judgment back on
the SAME declaration -- so record_lit_instantiated_fields does not fail to add
an expectation, it preempts a working one. Instrumentation then showed
authored_fte="" BEFORE substitution: substitution faithfully returns the
nameless node it was given, and the declaration reached by the ident-keyed
lookup is already identity-stripped where the name-keyed lookup's is not.

PAIRED NONZERO. Every fail-open arm now carries a matched non-generic twin at
the same seam, same run, same binary: six zeros, six reds. Plus an
undeclared-name arm proving the generic module is compiled and its body judged.
The twin design also rules out "that seam is unchecked for any type", which a
bare perturbation would have left open.

FOUR DEAD ENDS, ONE CAUSE, established by reading the construction site rather
than by another build: ResolvedModule.module is the raw parsed node,
build_type_env folds THOSE items into the bindings, and resolve_item_types runs
later feeding resolved_item -- never the binding. ResolvedModule means
import-resolved, not type-resolved.

Also recorded: resolve_field is correct and has zero callers while its wired
sibling resolve_field_init does not, which makes it an incomplete migration
rather than dead scaffolding -- and a cleanup sweep deleting it would leave the
lossy hand-rolled copy as the only authority. Claim staked on the PR.

Still no code change: the remaining question is an ident-versus-intern
address-space read, and a fifth blind repair would repeat the pattern the first
four established.

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

* The class is two rows, and the corpus reds the closed one: report it rather than narrow the wall (#8901)

* The 8 and the 4 have different dispositions: the census rows encode the old answer (#8901)

* LexMatchThunk is not generic, so it is none of the three rows: a fourth mechanism, bounded by three baseline arms (#8901)

* Withdrawn: the generic carrier is the algebra, not the thunk -- one-variable pair puts the tokenize row in row (b) (#8901)

* WIP: (a) fork dissolution — field_declared_type_node, authority + mirror

* (a) mirror half restored: field_declared_type_node in v1_compiler_infer.rs

* Drop stray backup file

* (a) fork dissolution + measured (c) exposure; placeholder-carrier hypothesis refuted by execution

* (c) an UNESTABLISHED return type must not become a lambda's body expectation

* Install the emitted mirror for v1_compiler_infer.rs (regen candidate, not hand-tuned)

* Delete four dissolved frontier rows (observed=0), fix two ContentHash construction defects the wall caught, admit list literals at FreeMonoid

* (c) sibling: an UNESTABLISHED substituted param type must not bind a lambda parameter as an error type

* Install emitted mirror for v1_compiler_emit_rust.rs (clone elision from the established-type fix)

* BISECT ARM (not a landing state): revert (a) field_substitution_carrier, keep (c)

Diagnostic push on a draft PR to separate (a) from (c) by execution.

The floor caught 9 claims that pass on main and fail on this branch, every
one of them against an independently authored oracle, so main's pass was not
vacuous and this branch computes wrong values. Local floor OOMs (137) in a
session container, so CI is the only instrument at whole-corpus scope.

This arm reverts (a) only. It deliberately re-opens the row-(a) defect --
the kb2 RED will stop refusing -- and is NOT proposed for merge. Read the
floor line, not the arms.

Predicts: if (a) is the culprit, failed goes 9 -> 0 and the 6 samsung_dram
stale-quarantine rows stay unmasked. If (c) is, failed stays 9.

* Revert "BISECT ARM (not a landing state): revert (a) field_substitution_carrier, keep (c)"

This reverts commit 18b5ddc6261acd3c5398a5fc5429fd9ea2e48f63.

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Transport binding spine: one target-neutral semantic binding for all four transports, then Filesystem bindings + Rust renderer to restore the 03_ingest board (#8957)

* WIP: Bind the file-transport realization handler AND migrate rest/shell/local

* WIP: Transport binding spine: one target-neutral semantic binding for all fou

* Regenerate the stage0 mirror for the transport binding spine

review 54885 and deep-ant-102 both found the same thing: the de-fork existed in
the .dag authority and not in the mirror v1 actually runs from, which is
specification-without-execution in its textbook form -- the exact failure this cut
exists to close. Produced by claim_executor --required-regen; the candidate tree
drifted in exactly the four emit files this change re-typed.

Also moves an annotation to module-item grain (§4c refused it at body grain) and
records the fabricated-empty-base_url marker dependency beside classify_transport:
kind is discriminated by marker-field PRESENCE, so making base_url refusable
deletes the rest tag and reclassifies every rest transport as local. No binding arm
requires a base_url value; that repair owes an explicit kind tag in the same change
and is deliberately not taken here.

* Drop the dead classify_transport import from the rust emitter

Zero call sites since the de-fork: the rust backend consumes a BoundOperation and
no longer classifies anything. A live import of the classifier is what a reader
grepping 'does the target still classify?' finds first, so it reads as the fork
surviving. Found in re-review by smart-ram-730.

---------

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

* Classify rustc mechanisms across diagnostic codes (#8978)

* Classify rustc mechanisms across diagnostic codes

* Record cross-code classifier provenance

* Bind mechanism population to its measured ref

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>

* Locate the LexMatchThunk apply receiver-type loss (#8983)

* Locate LexMatchThunk apply receiver type loss

* Record the bounded pre-descent ordering null

* Reclassify the apply root as a representation gap

---------

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

* Refuse per-code board shares for emitter roots (#8979)

* Refuse per-code board shares for emitter roots

* Audit shared-types membership authority consumers

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Brian Searls <11205878+briansrls@users.noreply.github.com>

* Make impossible fn-field derives unselectable through aliases (#8985)

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

* Bind mock-totality witnesses to published corpora (#9006)

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

* The .dag parser fabricated an empty path and silently ate unknown fields: five refusal arms, one live specimen repaired (#8949)

* The parser fabricated an empty path and silently ate unknown fields: five refusal arms, one live specimen repaired

`parse_file_fields` substituted an empty string literal when `path:` was omitted, so
`transport file { }` and `transport file { path: "" }` produced byte-identical nodes. That is
not merely an unchecked state: `is_file_transport` is DEFINED as "carries a base_path", so the
fabrication made the absence unobservable to every downstream consumer -- an emit-side "declares
no path" refusal is permanently green by construction. The rust realization duly emitted a
filesystem write against "" with zero diagnostics.

The refusal belongs at parse, where an absent path is decidable from the tokens alone, and that
is where it now sits.

CENSUS of every parser field that defaults rather than refuses (132 `Absent =>` arms in
02_parse.dag; all but these are legitimate token-absence handling):

  * parse_file_fields base_path -- omitted path fabricated as "". DEFECT, refused here.
  * parse_rest_fields base_url -- omitted url fabricated as "". NOT a defect: omitting `url:`
    is the norm (the base comes from the service config) and an empty base plus a full-URL path
    template is the authored absolute-form idiom recorded in extdeps.transports.rest. It is a
    state-space conflation with its own lane, not a refusal decidable from the tokens.
  * parse_config_fields endpoint -- omitted endpoint fabricated as "". NOT a defect: `config { }`
    is legal and shell services have no endpoint at all.
  * four `_` fallthrough arms (config, rest, shell, file) -- an unrecognized field was parsed and
    THROWN AWAY. Same fail-open reflex one layer over, and it had a live specimen: this repo
    authored `transport file { op: READ, path: ... }` in extdeps.cloud.gcp and the `op: READ` was
    swallowed whole, never resolved, never reported. All four refuse; the gcp site is repaired
    (read is the default verb, so the semantics are unchanged).

MEASURED, not assumed. The corpus-wide parse gate against a binary rebuilt from the regenerated
mirror indexes 3880 modules from 2 source roots, exit 0 -- so outside the one gcp.dag site
nothing in the corpus was relying on a dropped field or an omitted file path. Regen produced
exactly one drifted file, v1_compiler_parse.rs, across the 132-file mirror.

EVIDENCE, enrolled: dag/test/claim/transport_field_refusal_witness_test.dag carries three
positive controls and five discriminating REDs, all 8 PASS under claim_batch. The controls reach
compile.emit; the five reds stop at compile.analyses, so the refusal is real and the harness is
discriminating rather than false-for-everything. Per DESIGN §4b(4) these stay enrolled as the
evidence the rung holds, not deleted with the machinery they replaced.

v1 admission: this serves the v2 self-host program -- the file-transport realization lane
(#8929) is exactly the consumer whose emitted write the fabrication corrupted. Semantics stay
frozen; this is a defect repair, not growth.

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

* Name the stage in the assertion, not just the outcome: the pathless-path RED could not tell parse from emission

Folding in a finding from #8937 (sleek-fox-685, relayed by deep-ant-102) that is correct and that
this PR's own oracle could not have caught.

Every RED here asserted `!compiles(source)` -- ONE BOOLEAN, which is green whether PARSE refused
the declaration or the parser fabricated "" and the EMISSION wall caught it downstream. Those are
exactly the two states this change separates, so the row watching it could not see the thing it
was watching: revert the parse arm, let the emitter catch the pathless case, and every `!compiles`
red in this file stays green.

Three rows, not the one that was asked for, because a single row could pass for the wrong reason:

  * w_red_pathless_file_transport_refuses_at_parse_not_emission asserts the parse class
    POSITIVELY (blocking `ParseError` >= 1) rather than by excluding the emission class. Naming a
    stage by exclusion still passes if some third, unrelated class is what refused.
  * w_control_unmodeled_verb_refuses_at_emission_not_parse runs the same two counters the other
    way, over a source the EMISSION wall refuses. Without it, `parse_blocking_count >= 1` is
    satisfiable by a counter that is nonzero for everything and `not_modeled == 0` by one that is
    always zero.
  * w_control_valid_file_transport_is_clean_at_both_stages reads zero from both on a clean source.

Both counters answer -1 on CensusNotRunnable, so could-not-measure fails the `>= 1` AND the `== 0`
assertions instead of silently satisfying one (DESIGN §5: top-as-ignorance is not top-as-answer).

MEASURED: 11/11 PASS under claim_batch on the merged tree. The open question before running was
whether a parse refusal reaches compile_dag_diagnostic_census as an observed blocking ParseError
row or as CensusNotRunnable -- if the latter, the -1 arm would have failed the row for a reason
unrelated to the wall. It is observed, so the stage assertion is real rather than accidentally
green.

ALSO: the discriminator fact recorded where the next author will hit it, as a `//` annotation on
v1.compiler.core is_rest_transport. Transport KIND is discriminated by marker-property PRESENCE,
so `rest_transport_node`'s always-written base_url -- filled from the "" that parse substitutes
when `url:` is omitted, which is the NORM -- is load-bearing structure, not a lazy default:
removing it reclassifies every rest transport in the corpus as `local`. It is also why
is_local_transport is defined negatively. Regen confirms the annotation adds no mirror drift.

Merged origin/main. Regen against the merged tree drifts ONE file, v1_compiler_emit_rust.rs, which
is main's own red (#8691 landed without its second regen pass) and is #8953's to repair -- not
regenerated here, because installing another lane's fix from this tree would give the corpus two
producers for one file. v1_compiler_parse.rs is byte-identical to a fresh emit.

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

* An annotation cannot fail: guard the kind-discrimination invariant the 00_core comment only described

deep-ant-102 measured what I did not: ZERO witness rows asserted the classification my annotation
documents. DESIGN §4c is explicit -- an annotation is never evidence a machine claim holds, because
no Accepted program can read one. Prose is the right home for the RATIONALE and cannot be the guard
for the INVARIANT, and a comment that reads as coverage to the next reader is worse than none.

That reading is not hypothetical: a review of this very PR called the comment "a nice defense
against a future 'consistency' edit". It is not a defense. These two rows are.

  w_red_rest_transport_classifies_as_rest_not_local
  w_control_shell_transport_emits_no_rest_client

Asserted through EMISSION SHAPE rather than by calling is_rest_transport, and that is a
reachability fact rather than a preference: CI's source roots are `dag` and `src/v2`, so
v1.compiler.core is not in the witness pool and the predicate cannot be named from a witness at
all. The consequence is the better subject anyway -- it runs the real pipeline instead of the
predicate in isolation. The control supplies the other answer so the first row is not satisfied by
an oracle that matches everything, which is the same defect the stage counters had before their
inverse row.

MUTATION-TESTED RATHER THAN ASSERTED, because "delete the fabricated base_url and this row fails"
was a claim about a RED I had not executed. Scratch build with the always-written url_field removed
from rest_transport_node -- the exact "tidy the lazy default" edit the annotation warns against:

  FAIL w_red_rest_transport_classifies_as_rest_not_local
  PASS w_control_shell_transport_emits_no_rest_client

The mutation reds the specific claim and not the harness. Reverted; `git diff` on the mirror is
empty, so nothing from the scratch build is in this commit.

13/13 PASS on the restored tree.

Kept here rather than routed to #8954's roster witness: this PR introduces the annotation, so it
should land with its guard rather than ship prose-only coverage and depend on another lane to close
it.

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

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

* End an unbraced arm body at a QUALIFIED pattern, not only a bare one (#8999)

parse_match_arm_stmts consumes statements until looks_like_arm_start
reports that the next tokens open a new arm. That predicate recognised a
bare `_` and an UPPERCASE-start leaf, and nothing else. A namespace-
qualified pattern begins with its lowercase module head, so it answered
false: the body kept consuming, swallowed the next arm's pattern as one
more statement, and the parse died on the FatArrow that followed.

The reported span is that ARROW -- several lines below the arm that
actually ended -- which is why this had to be bisected rather than read
off the diagnostic. Four separate reproductions of the neighbouring
shapes all parsed before the real one was found.

MINIMAL REPRODUCTION, every clause load-bearing:

    Kind { f: _ } =>
      let a = "p"          <- unbraced arm body containing a `let`
      a
    mod.path.Other => "d"  <- next pattern is DOTTED

Drop the `let` and the body is a single expression that never enters the
statement loop. Make the following pattern `_` or an uppercase leaf and
the predicate already answered true. Both are needed.

MEASURED. On the namespace-cut branch, where qualifying every pattern
turns this from rare into ordinary, exactly one corpus file of 3875
reaches it: src/v1/05_emit.dag. That file is invalid under the parser its
own branch carries -- it survives there only because the built binary
predates its own committed mirror, so the defect is latent and would
surface at that branch's first successful rebuild. This is therefore a
grammar gap the cut made REACHABLE, not an accommodation for it, and it
fails loudly at preparation rather than silently downstream.

DISCRIMINATING RED, BY EXECUTION: the witness returns false against a
parser with this one decision reverted to `false`, and true with it. Both
runs were performed.

ZERO-DRIFT, STRUCTURALLY: the new scan runs only where the old predicate
already answered false, and it requires the TERMINAL segment to be
uppercase with the arrow following the path or its brace group -- so no
previously-accepted parse changes, and a lowercase dotted expression
ending a body is unaffected. An expression statement genuinely followed
by a FatArrow was never a legal parse. Receipt: required-regen over the
133-module subject reports first_generation_equal=true with only this
repair's own mirror changed.

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>

* Bind a qualified pattern head from the scrutinee, as the bare spelling already does (#9004)

* Bind a qualified pattern head from the scrutinee, as the bare spelling already does

Two spellings of one pattern name the same declaration, so they must bind the
same node. lookup_variant_in_type forks on whether the head contains a dot: the
bare branch answers from the SCRUTINEE, which carries the instantiation; the
dotted branch answered from the SYMBOL INDEX, which returns the coproduct's
DECLARATION. So the payload bound to the declaration's type PARAMETER instead of
the scrutinee's type ARGUMENT, and every field read off it reported "no field
'root' on type 'T'" -- measured, not inferred, on a two-function probe whose
only difference is the spelling of the head.

Admission is unchanged: the index lookup still runs first and still decides
whether the head names a variant of this coproduct at all. Only the bound node's
source changes once admission succeeds, and the fallback arm reproduces the
previous answer exactly.

RECEIPTS. Discriminating RED proven in both directions on the same corpus: on
the pre-fix binary the qualified arm returns false with the diagnostic above and
the bare control returns true; after regen and rebuild both return true. One
generated file drifted -- v1_compiler_infer_patterns.rs, this repair -- and the
second pass reports first_generation_equal=true.

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

* De-confound the witness pair: the arms differed in imports, not only in head spelling

The floor reported the qualified arm at 58800ms CPU against a 5000ms budget with
1.21GB RSS growth while the bare arm passed under budget, and I read that as a
cost of the qualified pattern head. It is not yet evidence of that. The qualified
probe imported two names and the bare probe imported four, so the arms could
differ in source-closure construction, import binding, symbol-index use and cache
temperature as well as in the spelling under test.

The pair was a controlled experiment for the SEMANTIC discriminator and not for
the cost one -- a control must name its adversary, and cost was an adversary
these arms never excluded.

Both probes now import all four names, leaving the two pattern heads as the only
difference. The semantic RED is unchanged and was re-proven in both directions
after the edit, against binaries built from the pre-fix and post-fix mirrors:

  pre-fix   qualified=false  bare=true
  post-fix  qualified=true   bare=true

No generated file changes; the seed is untouched by this commit.

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

* Move the witness to the census grain: it was measuring emission for a claim about resolution

The subject is a BINDING fact and a binding fact is decided at typecheck. The
witness asked it through compile_dag_rust_emit_check, which parses, resolves,
typechecks, EMITS RUST, and then -- per the compiler's own
compile_dag_diagnostic_census_row_note -- collapses the whole result to a Bool,
discarding which judgment fired. The enrolled claim duly cost 58579ms CPU
against a 5000ms budget with 1.21GB RSS growth while its bare control passed
under budget.

compile_dag_diagnostic_census reports the causal judgment directly as typed
rows. That makes this witness narrower in subject, MORE discriminating -- it
names the diagnostic instead of collapsing to false -- and cheaper for a
principled reason rather than a convenient one: emission is downstream of the
fact being tested, so removing it removes work, not evidence.

CensusNotRunnable is a failure carrying its own cause and is never the expected
red. Could-not-measure and measured-nothing are different states and only one
of them is evidence.

MEASURED, one fixture, both probe sources carrying identical imports so the only
difference is the two pattern heads:

  pre-fix   qualified  OBSERVED[1] InternalError | no field 'root' on type 'T'
                       | blocking=true | n=1   (enrolled fn returns false)
  pre-fix   bare       OBSERVED[0]
  post-fix  qualified  OBSERVED[0]             (enrolled fn returns true)
  post-fix  bare       OBSERVED[0]             (enrolled fn returns true)

THE COST OBSERVATION IS NOT REPAIRED BY THIS CHANGE AND IS NOT CLAIMED TO BE. It
is carried forward in the pull request body with its two ruled-out causes, its
unattributed owners, and its next discriminator.

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>

* Three prose rows still said srv4 commits six, and the disk arithmetic behind them refuses at twenty-one (#9001)

The CPU-axis change (#8976) moved srv4 from 6 to 21 and left three prose rows
asserting the old width. Prose cannot refuse, so nothing surfaced them -- they
were found by review (fierce-hawk-734) rather than by any gate.

gunbc_runner_slot_allocation_srv4_admission_note said "srv4 commits 6 slots at
the memory axis" and that runner_count and the roster "both name 6 as the
materialization target". Replaced, not annotated: two accounts of one width is
what this module exists to prevent. srv4 memory-admits 29 and commits 21, the CPU
axis binding, and neither number is authored -- runner_count derives from
gunbc_runner_slots_per_host, so the note is a reading of one authoring.

width_is_a_minimum_over_axes_note carried the same six in passing. Corrected.

gunbc_runner_slot_width_ruling_note is deliberately NOT edited. It is labelled
SUPERSEDED AND RETAINED AS METHOD with "PRIOR TEXT FOLLOWS UNEDITED", and its own
header warns that reading on for current widths will mislead. Editing preserved
historical text to agree with the present would destroy the only thing it is for.

THE DISK ARITHMETIC IS THE PART THAT IS NOT COSMETIC.

srv4_runner_count_disk_cap_note sized the per-slot charge at width 6 and read as
reassurance. At width 21 the same charge is 21 x 40.96 GB, about 860 GB, against
a Samsung 970 EVO 500GB -- so runner_width_disk_preflight is EXPECTED TO REFUSE
srv4 at its committed width. The allocation axis cannot see this: disk is
DiskWidthUnconstrained at allocation by the 2026-08-06 ruling. So the model
commits a width the actuator is expected to stop, which is the fail-closed arm
working and also means srv4 has a committed width it cannot currently reach.
Recorded rather than resolved by lowering the commitment, because absorbing to a
width the disk happens to permit is the fallback that ruling removed.

AND THE CHARGE IS CIRCULAR, which is recorded at the authority rather than only
in the rows citing it. runner_slot_disk_budget_per_slot_note claimed provenance:
"derived from srv4_runner_count_disk_cap_note arithmetic (~38GB per slot at width
7 on 500GB class disk)". That is not a provenance -- disk size divided by the
width of the day IS the derivation, so the charge was computed FROM a desired
width and is now used to CONSTRAIN one. Nothing was measured. A live observation
under an active reclaimer came in near 2.5 GB, two orders of magnitude below it.

So a circular charge is refusing a derived width: two unmeasured numbers meeting,
and neither the refusal nor a pass would be evidence about srv4's real disk. The
refusal stays, because refusing on an unreliable charge is fail-closed and
lowering the charge to make the width fit would be fitting the measurement to the
answer. What is NOT claimed is that srv4 cannot hold 21 slots -- every ephemeral
runner keeps a _work tree plus caches, so the true figure is not 2.5 GB either
and the question is open in both directions. Each row carries the same
dissolve-on: a measured per-slot disk series on srv4.

Co-authored-by: Brian Searls <briansearls1@gmail.com>

* Make the hand-built argv unwritable at the call site, and land the positive examples that show what to write instead (#8919)

* Make the hand-built argv unwritable: seal ArgvCommand, and land the builders that show what to write instead

extdeps.exec.command ArgvCommand becomes sole_constructor with one admitted
mint (argv_command), caller-sealed by name to typed builders homed in each
tool's own extdeps module beside its cited upstream authority. All 58 record
constructions on main are converted in this change, because a partial seal is
a dual-authority interval rather than a weaker seal (DESIGN section 3).

The carrier splits program from arguments, which makes the empty argv
unrepresentable and dissolves two runtime refusal arms in gunbc.command_runner
(DESIGN section 4b: structurally impossible over mechanically preventable).

The seal surfaced nine hand-spelled argvs that were never record literals and
four List<String> laundering seams; all are converted or closed.

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

* Program spelling is an observation claim: one authority paragraph, one line per row

still-seal-394's correction: the rule is not 'PATH-resolved is the safe
default'. An absolute path is a claim that this repository observed the
target's filesystem, and it is the STRONGER form wherever that claim is true --
a sudoers rule can name it and a preflight can test for it. PATH resolution is
correct only where the host is unobserved.

The reasoning, the climb criterion and the roadmap_dashboard_instance_apply
counter-example live once at extdeps.exec.command
program_spelling_is_an_observation_claim; the ten rows it governs carry one
line pointing at it instead of ten copies of the paragraph.

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

* Five more hand-spelled argvs the seal surfaced: /proc reads and the fd walk

The refusal census does not stop at the record literal. build_cache_endpoint_observe
still spelled four argvs as bare word lists (two cat, one stat -c %U, one
readlink) and host_effect_realize spelled the /proc fd walk as a fifth; all five
now derive from cited authorities, with find's -lname glob fact homed in a new
extdeps.tools.findutils beside the flags rather than in the caller that met it.

stat's name row gains the -- end-of-options guard its sibling rows already
carried: one module was answering one question two ways, and these operands come
from observed host state, which is exactly where a leading-dash path appears.

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

* Cast the two NonEmptyStr literals at their call sites

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

* Admit two builders the wall caught, and measure the NonEmptyStr refinement the climb rests on

The seal refused readlink_command and the findutils fd-walk builder -- two
admit-list omissions of mine, caught by execution rather than by review.

The empty-argv climb claims program: NonEmptyStr makes an empty program
unwritable. NonEmptyStr is a refinement, not a mint, so that claim is only as
good as its enforcement at construction. Measured with a discriminating pair on
a freshly built gunbc: data p: NonEmptyStr = "" is REFUSED at the declaration,
data p: NonEmptyStr = "mkdir" is accepted and evaluates. Recorded beside the
deleted test, with the path boundary and the reason it is not enrolled.

Two NonEmptyStr literals become data rows, because a cast of a String literal
at a call site is refused by the same judgment.

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

* Count the sh -c residual instead of estimating it: eleven, not six

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

* The nbd programs do not both run on the BMC: correct the note that said so

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

* State the two privileged word changes at the builder that makes them

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

* Name the two concrete products the hub still carries, and why the rule admits them

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

* The transport-argv population is blocked by a floor defect, not this lane's residue

Preliminary ruling relayed from the shell -> dag lane: an identifier in a
transport argv position is never name-resolved, so no citation-based conversion
of those sites is possible by any author until gunbc#8916 closes. Naming it as
residue would read as a conversion that stopped short and would put the
obligation on the wrong lane.

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

* State the empty-program climb as four facts, not one claim

Operator ruling relayed: a completed climb retains executing evidence, and this
one has a recorded receipt with no enrolled route. The arms stay deleted -- the
empty argv is unrepresentable regardless of enrolment -- but the claim is
evidenced-but-not-floor-enrolled on the source path and unmeasured on the
emission path, stated as separate facts so they cannot collapse into 'done'.

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

* The bracket-form regression control follows its builder's rename

socket_inode_holder_argv became socket_inode_holder_command when the /proc fd
walk stopped being a hand-spelled argv, and this witness -- the control that
pins the ? wildcards against the bracketed glob that silently matches nothing --
still called the old name. CI caught it; I had not.

It asserts exactly what it asserted before: the emitted pattern is
socket:?3894042? and contains no brackets. Only the route to the words changed,
from a List<String> return to argv_words over the ArgvCommand.

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

* One name, two operations: qualify the ten live-deploy references the merge made ambiguous

THE MERGE PRODUCED A COLLISION NEITHER SIDE COULD SEE ALONE. main's #8845
added `gunbc.live_deploy.operations.rm_force_command(paths: List<String>) ->
String` -- privileged shell TEXT for removing several paths. This branch added
`extdeps.tools.gnu_coreutils.rm_force_command(path: String) -> ArgvCommand` --
the cited tool operation for one path. Different layers, different carriers,
different arity, same spelling. Each was unambiguous in its own tree.

THE COMPILER REFUSED RATHER THAN PICKING, which is the outcome worth recording:

  dag/gunbc/live_deploy/emit.dag:818:29: error: ambiguous reference
  'rm_force_command': 2 candidates: extdeps.tools.gnu_coreutils.rm_force_command,
  gunbc.live_deploy.operations.rm_force_command — qualify by containment path,
  alias, or rename

Ten references, six in `live_deploy/emit.dag` and four in its test. All ten
want the shell-text one -- they pass `paths:` and feed `deploy_raw` -- so they
are now spelled `gunbc.live_deploy.operations.rm_force_command`. Qualification
is the diagnostic's own first suggestion and the least invasive of the three:
it edits references, not authorities, and renames nobody's landed symbol.

NEITHER NAME IS WRONG, which is why this is not a §3 nicknaming repair. §3
forbids two names for one concept; this is one name for two concepts, and both
are honest in their own module -- `extdeps/` keeps the tool's real operation
name, and the product layer names the privileged-text form it owns. If either
should move it is a question for the live-deploy lane, not something to settle
inside a merge.

ONE LATENT INSTANCE LEFT DELIBERATELY, named rather than silently passed over:
`dag/gunbc/build_cache_endpoint_path.dag:130` calls the unqualified
`rm_force_command(path:)` and did NOT error, because
`gunbc.live_deploy.operations` is not in that module's import closure. It is
correct today and one import edge away from the same refusal -- the same
closure-scoped resolution class this session filed as gap-analysis row 30
(gunbc#8943) and repaired four sites of in gunbc#8944. Left unqualified because
this PR is otherwise complete and a speculative edit buys a 40-minute CI cycle;
recorded here so the next reader finds it by search rather than by breakage.

Regen passed on this head (first_generation_equal=true), so the inherited
#8691 red is gone and this floor refusal was the only remaining failure.

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

* Merge main (§4c annotation fix, #8989) and align the one over-indented admit row

THE MERGE closes the last inherited red. #8989 hoisted the §4c-illegal
annotation out of `witness_retired_runner_slot_owner_refuses`'s match body;
while it stood, floor preparation died before planning a single witness, so
every "failing" floor verdict recorded anywhere in the repository during that
window was uninformative rather than negative. This branch's own runs in that
window say nothing about this branch.

THE NIT, from review 54984 and held deliberately until now: one `decl_ref` row
in `argv_command`'s `admit_callers` list sat at 8 spaces where its 39 siblings
sat at 4. Now 40 of 40 at 4. It is cosmetic, which is exactly why it waited —
pushing it alone would have cancelled an in-flight run, dropped five approvals
(scored per head), and spent a ~45-minute CI cycle in a fleet completing about
one run in six, all to correct four spaces. Riding the merge costs nothing.

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

* Two witnesses caught the spelling migration going both ways, and only one of them was the witness's fault

THE FLOOR RAN FOR THE FIRST TIME ON THIS BRANCH and reported failed=10 against
main's failed=8 on the same head (13db52a25, run 32621117917). The two extra
are mine. They are opposite defects and the difference is the whole entry.

BUSYBOX -- MY CODE WAS WRONG, THE WITNESS WAS RIGHT.
`busybox_build_is_modeled_and_grounded` asserts `'mkdir' '-p'` and got
`/usr/bin/mkdir`, because this migration routed the call through
`mkdir_parents_command`, whose wrapper cites the recorded absolute path.
`gunbc.busybox_bmc_build` runs its whole sequence under `LocalExec` on whichever
machine the operator invoked the cross-build from -- it demands an
`arm-linux-gnueabi-` toolchain, not a host this repository has ever read. So the
absolute path was a claim about an unobserved filesystem: the exact §5
fabrication `extdeps.tools.mkdir`'s own rows warn against, committed by me while
quoting the rule. Now routed through `mkdir_parents_command_at` with
`mkdir_path_resolved_program`, with the reason stated at the call site as that
module asks its PATH-resolved callers to do.

The mkdir note is corrected in the same commit rather than left standing: it
said the BMC applet was the one such caller and "every other caller gets the
recorded absolute path". That became false the moment this second caller landed,
and a note asserting a population it no longer has is the stale-recital class
DESIGN §3 exists to stop.

SUDO -- MY CODE WAS RIGHT, THE WITNESS PINNED THE OLD SPELLING.
`srv4_runner_installer_command_cites_installer_with_env` asserts
`'sudo' '-E' 'bash' ...` and now renders `/usr/bin/sudo`. That change is
deliberate: sudoers matches on the absolute path, so a PATH-resolved spelling
would let the caller's own PATH decide which binary crosses the privilege
boundary, and `sudo_elevate` two functions above already used this row -- the
alternative was two spellings of one binary in one module. The assertion is
updated to the new words.

THE ASYMMETRY IS THE POINT. Same migration, same kind of diff, two witnesses
red, and the correct repair ran in opposite directions -- one edits the code,
one edits the oracle. Deciding by which side is easier to change would have got
one of them backwards; deciding by whether the host was OBSERVED gets both right.

Also lands the annotation I owed at `sudo_binary_path` (review 55022): the -E
row documented its own `-n` delta while the path delta was left implicit. Both
are now stated at their rows.

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

---------

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>

* A cost-shape defect that measured linear: file the per-step emit constant, and the refuted hypothesis (#8988)

* A cost-shape defect that measured linear: file the per-step emit constant, and the refuted hypothesis

I proposed fixing a quadratic accumulator in the orchestration emit path,
measured it, and it does not exist. The refuted hypothesis is the more useful
half of this row, so it is filed with the measurement rather than dropped.

WHAT WAS HYPOTHESISED, and every sentence of it is true.
v2.compiler.emit_orchestration orch_emit_steps_from folds left-linearly,
carrying the accumulated script as a String and calling orch_emit_join2(left:
everything_so_far, right: next_step) once per step. That join is not a concat:
it reaches orch_emit_from_registry, builds a TargetModel whose binding
spellings carry both operands verbatim, and runs the whole grammar emit pass
over it. Read that way it is n-1 emit passes over payloads growing to the full
script length -- the copied accumulator DESIGN section 6 names.

WHAT IT MEASURES. A scaling probe -- identical trivial steps, only the count
varying, release claim_batch, thread CPU with wall within 1-5ms on every row:

  n     8    16    32    64   128  |  128   256   512  1024
  cpu  48    61    94   161   308  |  239   448   894  1863
  ratio      1.27  1.54  1.71 1.91 |       1.87  2.00  2.08

Linear across two decades, no knee. A quadratic converges to 4.0 per doubling;
this converges to 2.0, and the early sub-2.0 ratios are the fixed intercept
washing out. Fit: about 14ms + 1.8-2.3ms per step, the slope moving between
processes on one box with ambient contention -- the same 2x spread
gunbc.witness_row_cost already records.

SO THE CONSUMER'S COST IS ARITHMETIC. test.claim.live_deploy.emit
twin_and_production_configure_disjoint_tailscale_endpoints budget-refused a
required floor run at "at least 5008ms" against
v2.workflow.required_floor required_floor_claim_cpu_safety_limit_ms. Run alone
it PASSES at cpu=5489ms wall=5504ms -- 5008 was the interrupt point, not the
cost, so the row is ~10% over the fail-stop rather than ~0.2%. At ~2ms/step its
four scripts are roughly 2750 rendered lines.

WHY THIS IS NOT A SECTION 6 ALWAYS-FIX. That rule fires on a PROVEN cost shape;
a plausible one is a hypothesis. There is no wrong complexity class here, only
a large constant, and reducing it means memoizing the emit path on
declared-input content -- the Realization/content-hash carrier section 2 holds
up as canonical and section 6 records v2 as still hand-rolling. Compiler-wide
work on load-bearing files, filed rather than improvised.

THE CLASS. A mechanism reading is not a cost measurement. The hypothesis named
the right function, the right call and the right reason it is expensive, and
was still the wrong complexity class, because whether a real mechanism
DOMINATES depends on constants the source does not show. The tell is that the
fix would have looked principled: orch_construct_seq2 is left "\n" right over
two raw operand tokens, wrapping and escaping nothing, so it is associative and
a rebalanced join tree renders byte-identical output. The rewrite was
available, correct, byte-safe and pointless -- and merged, nothing afterwards
would have distinguished it from a real fix.

WHAT WAS DELIBERATELY NOT DONE. The witness was not split: it would zero this
row's failure frequency while leaving sixteen siblings at ~8x the 500ms wall
migration threshold, which is the absorbing fallback executed at authoring
time, and the disclosure gate exists to keep that population visible. The
fail-stop was not touched. No declared-ceiling lane was built -- the
diagnostic advises one and no such mechanism was found in tree, which is
recorded as an observation about the diagnostic.

The row stays on the disclosure roster and will intermittently budget-refuse on
main until the memoization lands. Named as a real intermittent red, not an
acceptable one.

Every symbol and module cited here was grep-verified against the tree; no
positional citations (DESIGN section 3).

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

* "Two scripts each" was an unverified quantifier, and correcting it moved the finding

The approving review found nothing; re-reading my own row did. Two defects,
and the second one changes what this row says is worth fixing.

THE QUANTIFIER. I wrote that the sixteen live_deploy.emit siblings emit "two
scripts each". Counted per witness, twelve emit ONE, three emit two, one emits
three, and the refused row emits four. I had counted the family and not the
scripts, and asserted the second as though I had.

WHAT CORRECTING IT EXPOSED. With the real counts the seventeen observed costs
regress cleanly on script count:

  ~2235ms fixed per witness + ~773ms per emitted script

  scripts  rows  observed        predicted
  1        12    2830-3178ms     3008ms
  2         3    3841-3979ms     3781ms
  3         1    4109ms          4555ms
  4         1    5504ms          5328ms

The ~773ms marginal matches the probe's ~2ms/step over roughly 400 lines per
script, so the emit constant explains the SLOPE. It does not explain the
INTERCEPT -- and the intercept is the larger term for twelve of the sixteen.
About 2.2 seconds is spent before the first script is emitted, outside
orch_emit_pipeline entirely, and this probe did not measure what it is.

WHY THAT MATTERS RATHER THAN BEING A REFINEMENT. The previous revision took
5504ms, divided by ~2ms/step, and reported "roughly 2750 rendered lines, about
690 per script". The slope only accounts for about 800. I had folded an
unmeasured fixed cost into a measured per-step figure and published the
quotient as though the whole row were emit -- the same class of error as the
hypothesis this document exists to record, arrived at one layer further in.
So the row now names the fixed term as unmeasured and unowned instead of
absorbing it, and says plainly that it, not the emit constant, is the bigger
target for most of the family.

The split-the-witness paragraph now cites the regression's ~3781ms for a
two-script witness instead of "about two scripts and under the fail-stop".
The refusal to split is unchanged and unaffected.

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>

* Supplier bindings, per-supplier billing quantum, and an acquisition simulation (#8960)

* wip: ubicloud supplier binding (verifying)

* Billing quantum is a per-supplier fact, and continuous capacity is the modeled advantage of owning

* The acquisition question: does demand shape make a commitment worth holding

* fix: named fold args, no block lambda, no next-line field values

* refactor: qualify Offer/SelectionPolicy as SupplierOffer/SupplySelectionPolicy

'Provider', 'Offer' and 'Selection' each name two unrelated things in this
corpus: gunbc.dispatch_selection's ProviderOffer is an agent-runtime
credential binding carrying no price, and product.fabric.supply's Offer is a
priced compute-supply ask. They do not unify -- there is no proven coincidence
to bundle, only a shared English word -- so the generic name goes to neither.
dispatch_selection already qualifies its side; this qualifies ours.

* fix: bill the quantum against each job's duration, not the slot's concurrency

Executing the witnesses caught a units error in the simulation's billing core.
quantum_billed_slots(used_slots: taken, ...) passed a JOB COUNT into a
parameter meaning a DURATION, so a 60-slot minimum increment rounded a slot's
concurrency up to sixty instead of billing each of its jobs for sixty. Both
magnitudes are Nat, so it typechecked; only running it disagreed.

Replaced by billed_slots_per_job, which states the model's standing assumption
-- one slot is one job's runtime, and jobs of differing duration are not
modeled until arrivals carry a duration -- rather than leaving it implicit.

The shape witnesses were reworked in the same pass because their fixture moved
two axes at once: a 60-slot increment against one-slot jobs is so dominant that
owning wins under every arrival shape, which is a real effect but not the one
those tests claim to measure. Renting now bills per slot there, so demand shape
is the only thing varying, and the increment gets its own witness. The flip is
now demonstrated at EQUAL MEAN -- flat ten every slot versus six hundred once
in sixty, the same 6000 job-slots -- where it previously compared unequal means
and asserted the …
briansrls pushed a commit that referenced this pull request Aug 23, 2026
… it (#9027)

`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: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.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>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 24, 2026
…ing on

CI on a4f3e69 went red with FAILED PHASE parse (52 errors), all 52 on
one file this branch does not touch:
dag/test/manual/command_runner_local_argv_receipt_test.dag. It is the
§4c refusal for an annotation that names no subject -- #8919 left a `//`
block at end-of-file with no declaration following it. Main repaired it
in 1ed0205 (#9027); this branch was cut before that commit and
carried the broken file forward.

The floor phase passed. The KNOWN-RED-RUNTIME-ERRORED lines filling the
log are reported-not-gating by construction and are not why the run went
red -- reading them as the failure would have cost an hour on the wrong
subject.

Both merge conflicts were GENERATED artifacts -- DESIGN.md and
.github/workflows/witnesses.yml -- while all three of their authorities
merged clean with zero markers. Resolved by regeneration rather than by
hand-editing bytes nobody authored: a hand-resolved generated file is
drift the next regen deletes silently, which is the same failure this
branch already had to repair once.

Verified by content, not by the merge succeeding: DESIGN.md differs from
origin/main by exactly one line (this branch's rung-drop row), carries
the corrected bounded-population wording, and still carries the §4b
passage ported in earlier. The regenerated witnesses.yml has zero `cited`
references -- the deletion holds -- and picks up main's new toolchain
step.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HBx8dnz3oCiiHXoSBdtH2
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>
briansrls pushed a commit that referenced this pull request Aug 25, 2026
#9163)

Two main reds in one evening, and a third pair before them, all one class:
two PRs independently green, jointly broken. #9049 with #9114, #9057 with
#9062, #8919 with #8992. No textual conflict in any of them -- the first
change altered a semantic API and the second was checked against a base
where the old API still existed, so both greens were true of trees that
never existed together. The #9057/#9062 pair took the whole fleet red for
about an hour and produced four uncoordinated repair PRs plus a fifth
branch, two of which proposed deleting live code.

No wall inside this repository can close that. The invariant needed is that
the commit admitted to main is the exact composed commit that passed the
required checks, and nothing in the substrate can constrain what GitHub
admits.

WHAT THIS CHANGE IS: the in-repository half, and it is INERT ON ITS OWN.
witnesses.yml listens only to workflow_dispatch, push and pull_request, so
enabling a merge queue today would create a merge-group commit for which the
required check never schedules -- pending forever. This adds the trigger so
the prerequisite exists BEFORE the setting is changed, with no window in
between. With no queue configured the event never fires, so CI behaviour is
unchanged by this diff.

WHAT IT IS NOT: the repository setting. The ruleset currently carries
strict_required_status_checks_policy false, no merge-queue rule, and an
always-bypass role. That is an operator decision and this PR does not
presume it.

MergeGroup already exists in extdeps.github.actions WorkflowTrigger and the
YAML emitter already renders it, so this is one row, not new modelling.

EVIDENCE, including what I could NOT establish. Evaluating the workflow
authority on this branch and on clean origin/main gives byte-identical
diagnostic sets (2232 lines, zero diff), so nothing is introduced. I could
NOT run the emitter to regenerate witnesses.yml: the local gunbc shim is a
Jun 26 build that cannot resolve this corpus. The one yml line was derived by
reading the emitter -- `MergeGroup => kv(key: "merge_group", value: YamlNull)`
renders exactly as `workflow_dispatch:` does, in the position its entry
occupies in the `on:` list. DESIGN records the generated-artifact drift gates
as currently unguarded, so nothing will catch that line if I have it wrong,
which is why it is stated rather than assumed. Regenerating in CI and
diffing is the check I want on this PR.

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