Repository navigation
General orchestration intent to Bash emit fold over grammar rows - #5828
Conversation
…mmar row orch_emit_pipeline composes per-construct grammar rows by emitting each child intent to Bash and binding its string into the parent production (orch_seq2), then emitting the parent — every string comes from emit() over a grammar row, no translate-stage change. Fold lives in v2.workflow (compiler consumer), rows stay in bash.dag. Witnesses prove a 2-step Pipeline emits newline-joined by execution plus a discriminating space-joined perturbation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…d (general grammar rows) Add general grammar rows (Assign/If/AndOr/Pipe/WithRedir/EnvPrefixed/Heredoc + program set_e wrapper) and their emit_shell_stmt / emit_shell_program arms, each byte-identical vs the program.dag serialize oracle with discriminating teeth. 25 witnesses green by execution under both source-roots. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… grounded in real build_step_transport fragments
Add the two nameable bash constructs the build_step_transport migration needs
(path-redirect, negation prefix) as permanent program.dag model variants, with
disposable serialize arms for totality. emit_redir recursively emits the
RedirToFile path word; bash_stmt_negation grammar row emits the '! ' prefix.
Witnesses ground the new operators in the REAL harness spellings
('> "$PROBE_BIN"', '! (...)') — NOT a fresh serialize arm (anti-circular).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rminism for multi-orch_raw-token rows); keep grammar union coverage + RedirToFile/Negation + lex-completeness fixes Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ge env-bearing; strengthen held-welds witness GAP 1 (§2 keystone fork): orchestration_emit's orch_emit_run no longer stands beside the general shell_emit fold unexplained. Env-FREE Run now lowers to RawLine(command) and delegates to emit_shell_stmt (single orch_raw green path, proven byte-identical by orch_run_empty_env_delegates_to_shell_emit). Env-BEARING Run lowers to EnvPrefixed (multi-orch_raw) which hits the emit-kernel straddle, so it stays on orch_run_emitted_command (orch_emit_run_env_welded) under a new on-carrier dissolution trigger sibling to the held-welds one. Delegate the green part, stage the blocked part. GAP 2: bash_held_welds_dissolution_trigger_recorded_holds strengthened from a !="" proxy to string_contains teeth — asserts the trigger names each held weld + the kernel-debt straddle condition + DISSOLVES WHEN. Goes red if the marker is edited to drop them; the held welds' continued existence is already proven by the bash_emit_*_holds consumer tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Design final-sign (by my own execution) on head Verified: GAP1 (4/4 PASS on orchestration_emit_test.dag, both source-roots) — env-free Run now delegates to Remaining merge gates are outside the design: a 2nd distinct approval provider, and CI green — currently blocked on the runner-OOM infra (the — sent from neat-fox-547 |
…tor verdict, not free debt review 55258 is right and the correction is worth more than the file. The runner's header claimed that composing an existing scaffold "adds no new debt beyond the one it composes". That is self-authorized dissolution, which DESIGN.md names as a failure mode by that name, and it was wrong on its own terms: a second removable unit is a second obligation that whoever deletes the first must also find, and a trigger the author writes is a lifecycle fact rather than permission to create the debt. So the header now says what it is -- a hand-authored shell orchestration scaffold, DESIGN §6's out-of-band-actuation tell -- names the concrete dissolution trigger (#5828 bash-emit or a modeled cssl_probe transport, at which point the file is deleted rather than ported), and states that it lands only on an operator verdict on this exact exception. That verdict is requested, not asserted, and it is external to this diff by construction. Deletion is a live option and costs nothing that has already been measured: the fifteen logs, their sha256s, the probe rows and the join are committed data, and curated_cargo_probe_one.sh takes a board without this file. What deletion costs is the mechanised roster read -- the only non-diligence defence against the enumeration that produced three wrong populations in this fleet in one evening. The board README now says so where it tells a reader to run it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A67J8mYHNENb4yndcBrMD5
…stinct site (#9064) * Board the frontier by authority, and weight roots by distinct site rather than by summed board Two probe instruments, no production change. curated_cargo_board_cohort.sh boards the frontier roster in one process at one ref, reading BOTH the module list and each row's shim_lib_rel from dag/tools/self_host_module_behavioral_transport_roster.dag. Enumerating by glob, by grep on a field name, or by hand each produced a wrong-but-plausible population in this fleet inside one evening; the authoritative enumeration is mechanised here rather than left to diligence. It refuses a non-roster module, refuses a discarded log, and exits non-zero naming every board that line-stopped, so a partial cohort cannot be reported as the frontier. cross_module_mechanism_weighting.py joins those boards. Its point is that summed manifestations are not a defect count across modules: closures overlap, so one emitted defect is counted once per door it is visible through, and the sum rises when more entries are boarded with nothing changed in the tree. It reports distinct sites and breadth instead, at two declared site-identity strictnesses, because strict identity assumes an emitted file has the same bytes in every closure and that is precisely the assumption that can be wrong quietly. Root vocabulary is borrowed, not minted: cross-code identity from rustc_mechanism_classify, the E0308 15-root view from e0308_classify_sites carried as a code-local projection column. Rows with no established cross-code discriminator stay UNCLASSIFIED rather than being filled in from the error code. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A67J8mYHNENb4yndcBrMD5 * Make the cohort's ref and population an assertion the join executes, not the caller's diligence The weighting is a comparison, so its failure mode is not a weak measurement but a contaminant: a board taken at an unasserted ref is indistinguishable afterwards from a genuine per-module difference, and a board that line-stopped is indistinguishable from a module with nothing to report. Both are the denominator failing quietly, one through the ref and one through the population. --rows/--expect-sha refuse unless every board's own probe row declares the ref the caller declared, and unless the modules present as rows are exactly the modules present as logs. The two flags are one assertion and are refused apart, because half of it asserts nothing. Both refusals were executed against a planted wrong-SHA row and against a half-given flag pair. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A67J8mYHNENb4yndcBrMD5 * The frontier boarded fifteen ways: the shared floor is real, and every summed root size is 7x too big Fifteen of the sixteen roster modules boarded in one cohort at 6a59c1a (origin/main 1ed0205 plus two probe files the compiler does not read), and joined. Until now every root the repair queue is ranked on was traced from one entry. WHAT THE JOIN ANSWERS. Module closures overlap almost completely, so a per-module board cannot tell "one defect seen from fifteen doors" from "fifteen defects", and those have opposite staffing consequences. Deduplicating manifestations by site identity across the cohort separates them: 1709 manifestations resolve to 298 distinct sites, and on the eleven shim-free boards 92.3% of distinct sites appear on two or more modules. That confirms the standing H1 hypothesis in the root-partition plan by the exact falsifier it named -- real error texts, intersection measured rather than inferred from histogram similarity -- so the plan's H1 row is updated in place rather than left as an open question with the answer sitting in a probe. The reassuring half does not extend to magnitudes. Summing per-module figures overstates by 7.0x, and diagnostics-per-site varies five-fold between roots, so the inflation is not uniform and cannot be divided out. PRIMITIVE_REPR_FORK is four distinct sites carrying 104 manifestations; ABSENT_CLONE_BOUND is 22 sites carrying 129. Ranked by diagnostics they look comparable; ranked by what a repair edits they differ by a factor of five. TWO CROSS-CODE ROOTS ARE ESTABLISHED, both invisible to a per-code partition: PRIMITIVE_REPR_FORK spans E0308 and E0369 (the same emitted repr decision reported as a mismatch where a value crosses and as an unsupported operator where one is applied), MAP_CARRIER_FORK spans E0308 and E0560 (the E0560 half reads as an unrelated "struct has no field" family that no E0308 repair would close). 217 of 298 sites stay UNCLASSIFIED rather than being filled in from their codes. WHAT IS QUARANTINED RATHER THAN COUNTED. The four shim-bearing boards install a lane lib.rs that declares only its own lane's modules, so the rest of the closure refuses as unresolved crate-root paths: all 60 E0432 and all 16 E0608 manifestations sit on those four boards. That population is labelled SHIM_CLOSURE_GAP_instrument -- a property of how the board was taken, not a root -- and those boards' remaining unique sites are explicitly not claimed as module properties until they are re-boarded shim-free. THE SIXTEENTH MODULE IS ABSENT, NOT ZERO. program_assembly refuses before emitting with 26 hard name-resolution diagnostics in its own source. The absence is declared into the join, which refuses unless every board that produced a row also produced a log and every declared absence carries a reason; a cohort that quietly boards 15 of 16 and reports a weighting over "the frontier" is the empty-observation narrow. The fifteen cargo logs ship with their sha256s so this population can be re-partitioned without a rebuild; re-running the committed join over the committed logs reproduces the summary and the root table byte-identically. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A67J8mYHNENb4yndcBrMD5 * Classify the cohort runner honestly: a new scaffold awaiting an operator verdict, not free debt review 55258 is right and the correction is worth more than the file. The runner's header claimed that composing an existing scaffold "adds no new debt beyond the one it composes". That is self-authorized dissolution, which DESIGN.md names as a failure mode by that name, and it was wrong on its own terms: a second removable unit is a second obligation that whoever deletes the first must also find, and a trigger the author writes is a lifecycle fact rather than permission to create the debt. So the header now says what it is -- a hand-authored shell orchestration scaffold, DESIGN §6's out-of-band-actuation tell -- names the concrete dissolution trigger (#5828 bash-emit or a modeled cssl_probe transport, at which point the file is deleted rather than ported), and states that it lands only on an operator verdict on this exact exception. That verdict is requested, not asserted, and it is external to this diff by construction. Deletion is a live option and costs nothing that has already been measured: the fifteen logs, their sha256s, the probe rows and the join are committed data, and curated_cargo_probe_one.sh takes a board without this file. What deletion costs is the mechanised roster read -- the only non-diligence defence against the enumeration that produced three wrong populations in this fleet in one evening. The board README now says so where it tells a reader to run it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A67J8mYHNENb4yndcBrMD5 * State the sizing rule where the next person sizing emitter work will stand Requested by smart-ram-730 and relayed by the lane manager, with the placement argued rather than assumed: the 7.0x inflation and the five-fold sites-per-manifestation variance are PLANNING errors -- they corrupt which root you pick and how you rank roots against each other -- so they belong in the board a future sizer opens first, not re-quoted at nine repair lanes already past planning on one traced root each, whose two-arm measurements are unit-agnostic. The one exception is a lane whose acceptance test is an exact count, and the section says so rather than contradicting it silently. The rule ships with its own falsifying example beside it, because a rule alone is easy to misread: PRIMITIVE_REPR_FORK at 4 sites / 104 manifestations against ABSENT_CLONE_BOUND at 22 / 129 -- comparable ranked by diagnostics, five-fold apart ranked by what a repair edits, and the ordering reverses between the two units. That is the case that shows why the inflation cannot be divided out after the fact. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A67J8mYHNENb4yndcBrMD5 * Delete the shell runner and put its roster read in the join, where it cannot be skipped The runner needed an operator verdict and no one in this tree can supply one -- DESIGN puts scaffold approval external to the diff precisely because an author who writes a scaffold can equally write a row claiming it was approved, and a sibling session ruling on it is that same defect one level out. Rather than hold a finished board behind a decision it does not need, the runner is deleted: it was a composed convenience whose absence costs nothing measured, and DESIGN prices a throwaway at authoring plus review plus maintenance plus deletion plus review of the deletion against a benefit bounded by its lifetime. What the runner actually carried was not convenience: it was the mechanised enumeration of the cohort from the roster authority, which is the defence against the failure this lane exists to avoid -- a glob, a field-name grep and a hand list each produced a population close enough to pass a glance and wrong in the denominator, and a wrong denominator does its damage inside a comparison where it is afterwards indistinguishable from a real per-module difference. So that check moved into cross_module_mechanism_weighting.py as --roster, which reads the roster and refuses unless the cohort is exactly the membership it declares. This is a better home than the runner had: a runner is consulted only by whoever chooses to run it, while every published weighting passes through the join. Executed both ways -- the cohort passes with all sixteen rows accounted for, and dropping one module's board and row is REFUSED by name. The board is unchanged. Its README now documents boarding a module with the in-tree curated_cargo_probe_one.sh and passing that row's own shim_lib_rel, and says where the roster check went and why. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A67J8mYHNENb4yndcBrMD5 --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
… to a typed carrier DESIGN 4c: an ordinary String declaration whose sole purpose is commentary is misplaced data. The two prose notes this PR added move to standalone leading // annotation blocks on their module-scope service declarations. DESIGN 3/6: the expanded hand-authored shell now carries a typed DissolutionCondition naming bash-emit (#5828 / shell-to-intent Phase 2) rather than prose, matching gunbc.ci_spec's existing rows. Per the gunbc.githooks_pre_push_emit precedent this edits the failure arm of an EXISTING transport and adds no new emission site. The split is what 4c asks for: rationale to the annotation channel, machine- consumed facts to a typed carrier.
…dered as success with empty output (#9518) * A pipeline reports its LAST stage's status, so a failed entropy draw rendered as success with empty output Three shell transports ended in a pipe, so the exit status came from the stage that runs last rather than the stage that knows. Their `nonzero` arms could never fire for a producer failure. extdeps.entropy Urandom.ReadBytes head -c N /dev/urandom | base64 -w 0 extdeps.shell Find.FilesAndSymlinksWithMode find ... -printf ... | sort extdeps.shell Find.FilesByNameSorted find ... | sort The entropy one is the severe case and is not a listing problem: base64 succeeds on empty input, so a failing `head` is reported as EXIT 0 WITH EMPTY OUTPUT -- a successful entropy draw that drew nothing, on the one operation whose fabricated output is indistinguishable from the real one by inspection. The find pair produced a confident empty listing for a failed traversal, which both callers digest into a tree identity or manifest. MEASURED, not inferred from shape: sh -c 'find /nonexistent -type f | sort' -> exit 0 sh -c 'head -c 16 /nonexistent | base64 -w 0' -> exit 0 printf '' | base64 -w 0 -> exit 0 `set -o pipefail` is NOT the remedy: /bin/sh is dash on the runners this executes on and aborts on it rather than accepting it (measured). The status is captured from the producing stage, following the in-tree exemplar extdeps.rust.rustc (`...; rc=$?; rm -rf "$d"; exit $rc`). The entropy bytes travel through a file rather than a shell variable because command substitution strips NULs and would corrupt the draw. Behaviour: output byte-identical (A/B over a 661-line listing); the only change is the failing arm, from 0 to the producer's status. Each script executed in both directions -- happy path exit 0 with correct output, failing producer nonzero. NOT REPAIRED, needs its own owner: Urandom.ReadPassword builds components with unchecked `$(tr ... | head -c1)` substitutions, so a failing component silently yields a SHORTER password rather than a refusal. That is a different and more serious defect than the pipe status and a redesign of the generator rather than an argv repair; recorded in the module note. Found by crisp-cat-384 (from their own permanently-green listing arm) and routed via deep-ant-102; neither could take it without widening their ruling. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Escape the literal brace in the status note: {count} in prose is interpolation syntax The note explaining the pipeline-exit-status defect quoted the old argv as `head -c {count} /dev/urandom | base64 -w 0`. Inside a String, {count} IS interpolation, so the compiler resolved it as a variable and refused with 'undefined variable count' at entropy.dag:43:160 -- failing both the parse phase and the floor. The language already carries the \{ escape for exactly this (locked by test.claim.string_brace_escape_witness_test), so the fix is the escape, not a respelling of the quoted argv. The two remaining {count} occurrences are in transport argv where interpolation is intended. * Address review 56984: rationale to the annotation channel, shell debt to a typed carrier DESIGN 4c: an ordinary String declaration whose sole purpose is commentary is misplaced data. The two prose notes this PR added move to standalone leading // annotation blocks on their module-scope service declarations. DESIGN 3/6: the expanded hand-authored shell now carries a typed DissolutionCondition naming bash-emit (#5828 / shell-to-intent Phase 2) rather than prose, matching gunbc.ci_spec's existing rows. Per the gunbc.githooks_pre_push_emit precedent this edits the failure arm of an EXISTING transport and adds no new emission site. The split is what 4c asks for: rationale to the annotation channel, machine- consumed facts to a typed carrier. * Address review 57015: the shell dissolution trigger cited a fabricated symbol The trigger named shell.Find.ListDirs and shell.Find.ListFilesByGlob. Neither is right, and they are wrong in two different ways: ListFilesByGlob DOES NOT EXIST. No operation of that name is declared anywhere in the service. It was fabricated. ListDirs exists but is an unchanged DIRECT-ARGV operation -- argv is a plain ["find", "{path}", ...] vector with no shell, no pipeline, and no expanded string program. It is not scaffold this PR introduced and carries no debt. The operations that actually carry the medium-as-string shell are FilesAndSymlinksWithMode and FilesByNameSorted -- the only two whose argv is an `sh -c` program capturing the producing stage's status through a temporary file, which is the exact construction the trigger exists to dissolve. Both are named now and both resolve. WHY THIS IS THE SEVERE CLASS RATHER THAN A TYPO. A dissolution trigger is the receipt that admitted debt has a declared end. Pointed at a fabricated symbol it retires against nothing, and pointed at an unchanged operation it would have retired when a wall was built for scaffold that operation never had -- so the scaffold this PR does introduce would have kept its receipt while losing its subject. The debt reads as covered in exactly the state where it is not, which is worse than an uncited scaffold, because an uncited one still ranks for work. It is also DESIGN section 3's cite-the-symbol rule violated in the direction that rule is hardest to catch: a name that resolves nowhere is decidable by lookup, and I did not perform the lookup before authoring it. Both files' triggers are now grep-resolved against their own declarations -- entropy.dag's Urandom.ReadBytes / ReadPassword were checked by the same pass and were already correct, so this is a one-file defect and not a habit across the PR. --------- Co-authored-by: Brian Searls <briansrls@gmail.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Brian Searls <briansearls1@gmail.com>
…render review 61958, both findings verified and correct. THE BACKSTOP NO LONGER DERIVED THE JOB IT GUARDS. It was a hand-kept sum of per-step budgets, and this branch inserted a fourth step into the build job with its own 5-minute budget without adding a term -- so the job backstop could fire while every step was still inside its declared budget, and it would have read as a hung build rather than as a miscount. Rather than add the missing term, the sum now FOLDS the step list: fleet_converge_build_job_steps() is bound once and consumed by both the job's `steps:` and the backstop, so adding a step and adding its budget are the same act and the two cannot disagree. Construction where a check would have been the alternative; emitted backstop moves 65 -> 70. THE HAND-SHELL GATE CARRIED NO SCAFFOLD MARKER. The dispatch-admission step is a concat-built program handed to a foreign executor's `run:`, which is exactly the shape gunbc.ci_spec ci_release_bins_pack_shell_emit_dissolution_trigger names, and DESIGN section 6 is explicit that a MISSING dissolution condition makes the finding more severe rather than less. Added fleet_converge_reset_observer_admission_shell_emit_dissolution_trigger, following the sibling's form including emitting the description into the script as a comment, and naming the same trigger (bash-emit, #5828 / shell->intent Phase 2). AND A COST FINDING OF MY OWN, from CI on ae71183 rather than the review: BOTH witnesses I added in the previous commit were interrupted before verdict at 507ms and 509ms against the 500ms line. The measurement says rendering this workflow -- or constructing its five jobs -- is roughly the entire claim budget by itself, so splitting the org-admin-secret claim into its own identity was right on SUBJECT and wrong on COST: it rendered the workflow a second time for one extra string test. Both repaired at the mechanism rather than by budget: - the build-job witness folds fleet_converge_build_job_steps(), the same single authority the job consumes, instead of indexing fleet_converge_workflow -- one job's steps instead of five jobs, same question answered. - the org-admin-secret claim moved into the witness that ALREADY renders the workflow, which now asserts both absences over one render. Two demands, one frame as their least common ancestor, so the first value is carried. Net renders in the file are unchanged at two; my additions now cost no render at all. Both PASS. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe
…10739) * A reset receipt that cannot say a host returned when nobody looked The Mt. Collins canary receipt states its own limit: "one job on one boot -- nothing here shows a second attempt starting cleanly after a first, which is what a runner host actually has to do". This is the carrier for that missing property, and its whole design turns on one distinction: "the controller accepted the reset" and "the host came back" are two facts, not one. So there is no duration field outside the arm that observed both ends. The down and back instants exist only inside HostObservedDownThenBack; every other arm yields std.observation MeasuredUnavailable carrying its cause. A zero downtime is not guarded against, it is unwritable -- which matters because zero sorts to the top of any ranking of outage times. THE OBSERVER CANNOT BE THE SUBJECT, BY CONSTRUCTION RATHER THAN BY CHECK. A job running on the host it resets dies at the reset and cannot observe the return; what it wrote before dying is exactly the empty value that then reads as a positive answer. Every host-scoped converge mode today is an if-gated step in a job pinned to the selected host, so adding this mode the ordinary way IS the failure. The dispatch input is therefore inverted: it carries the OBSERVER label, runs-on consumes it directly, and the subject is not an input at all -- the entry learns it from the machine it is running on. There is no form field in which the invalid pairing can be stated. sole_constructor is enforced across module boundaries (measured: a witness spelling a pairing literal was refused), so the attempt cannot be assembled around a pairing nobody minted either. THE ROSTER IS AN IDENTITY JOIN, NOT A LIST. A host is a reset subject exactly when oob_boot_handoff_admission -- the fold the actuation arm already runs before it writes -- admits its observation against its capability row. The evidence that authorizes the act produces the membership, so the roster cannot drift from the capability it describes. It has one member today because exactly one host has ever landed a BmcAccessObservation. Four reds that were each a green reached for the wrong reason: - an accepted command with the host never down (the receipt that carries only the acknowledgement renders this as success) - a subject already down at issuance -- satisfies both watches in order and fabricates a complete reading of a reset that moved nothing - a down observation predating the issuance instant, so a stale liveness fact cannot testify to this reset - an observer that never converged its own hostname: it differs from the subject exactly as surely as a correct peer does, so the difference is real and establishes nothing The last of those is why observer_self_identity takes three names. The order of its two questions is load-bearing and has its own witness: a runner labelled as a peer but living on the subject chassis fails both predicates at once, and asking "have I converged?" first would report the substitution this check exists to catch as an ordinary maintenance problem. The second-attempt property is a relation over two receipts, computed. Two attempts sharing an artifact path, or carrying identical digests, or hashed under different families, all refuse -- appending to an earlier artifact changes the bytes its digest names, invalidating a receipt while leaving it looking valid. And the receipt splits from the observation because a run cannot honestly digest its own evidence: the transcript is not finished until the run is. Also: fleet_converge_enrolled_host_options is now derived from fleet_hosts() rather than spelled a second time, and mtcollins1 is named in fleet_intent_network and allocated a hostname -- naming is not enrollment, and it joins no executor roster. Not yet executed. The credential prelude is absent because authoring it means naming a pinned secret version nobody has authorized; until then the job dispatches, runs, and refuses on the missing path before any controller write. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * Name a timeout row that exists, and size the back-watch to the step that runs it The emission refused on an undefined `gunbc_ci_fleet_step_timeout_minutes`; the row this job's step wants is the one already imported here. Checking its value found the worse defect. The two watch bounds were round numbers picked without noticing that a sample costs different amounts on each side: waiting for the host to go DOWN the probe succeeds and returns at once, so a sample is about the one-second sleep, while waiting for it to come BACK the probe fails and carries ConnectTimeout=5, so a sample is about six seconds. Six hundred back-samples is an hour inside a thirty-minute step -- a watch the platform kills before the fold can return, and a killed job writes nothing, which is the empty value that reads as a positive answer. The bound is now derived from the step budget rather than chosen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * A declared refusal nothing could construct read as coverage Review 61729, both findings correct and the second showed a comment of mine asserting a refusal that did not happen. NoPeerAvailable was declared, matched in the emission gate, and constructed NOWHERE. The state it names is reachable: the selections fold mapped over the peer roster, so a subject with an EMPTY peer roster contributed ZERO selections -- and zero selections is not a refused selection, it is nothing at all. The subject then stopped being offered with no diagnostic anywhere, which is exactly the absorbing fallback the paragraph directly above the type forbids. A declared cause nothing can emit is worse than an absent one, because the type reads as coverage. And the note on the option list claimed "an unmintable one yields an EMPTY list that the emission gate below refuses on", which was false: an empty pairings list is DispatchAssignment, not DispatchAssignmentRefused, so the gate passed and would have serialized a reset_observer choice input with zero options -- a mode nobody can select, which is a capability removed silently rather than a diagnostic about one. Fixed at the mechanism rather than the comment. An empty peer roster now CONSTRUCTS NoPeerAvailable instead of falling through a map with nothing to iterate, and an empty subject roster refuses on its own new cause -- nothing to iterate is not the same as nothing refused, and both routes to an empty dispatch form have to be loud. The gate additionally refuses an empty admitted list, which is belt to that braces and says so. Three witnesses: the no-peer route, the no-subject route, and the discriminating red that no route yields an admitted-but-empty assignment. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * The new refusal cause made three exhaustive matches non-exhaustive Which is the wall doing its job: adding NoResetSubjectRostered to the cause coproduct reds every match that claimed to cover it, so no witness can silently keep asserting a partition that no longer holds. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * One path row for the writer and the step that prints it Review 61747. The invoke stamped receipt_rel "target/host-reset-return.txt" and gunbc_invoke_receipt_steps turns that into a post-run cat of that exact path, while the wet exit wrote target/host-reset-return-<attempt>.txt. So a SUCCESSFUL reset would have exited 0 and then failed on a file nobody wrote: a green inverted into a red by a second spelling of one path, and it would have fired the first time credentials existed. The attempt label is out of the filename, which is what made the fork unfixable rather than merely wrong -- the attempt is derived at run time from the machine the job landed on, so emit time cannot name the file. Two attempts are two dispatches with two workspaces and two uploads, so the run already distinguishes them; the label bought nothing on disk and cost the agreement. It moves into the receipt line, where it was always doing its work. The never-append discipline is untouched: it governs the COMMITTED artifacts a receipt names by digest. Also the second finding, and it is the same class this branch was already caught by once: a comment in the run module still said gunbc_fleet_hostname_allocations carried no Mt. Collins row and that the first attempt would refuse there. This branch adds that row. The claim was stale the moment it landed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * The label and the machine were one reading, so the corroboration was decorative Review 61761, and it is the sharpest finding on this branch. The entry keyed itself on `hostname -s`, so the label that decided WHERE the job ran and the name the machine ANSWERS TO were the same instrument. A runner labelled srv1 but living on the subject chassis, or a host that never converged and reports "ubuntu", then failed the assignment lookup as "not an assigned observer" and NEVER REACHED the identity check at all -- so ObserverIsTheSubjectMachine and ObserverHostnameNotConverged were reachable only from fixtures while this branch claimed them as the wall protecting the hardware. Specification-without-execution on the production route, and citing the wall while the acceptance path cannot express its red is rung inflation (DESIGN §4b meta-obligation 1). The dispatch observer label is now carried into the process by its own env row and the assignment is keyed on it, leaving the machine's own hostname as purely the corroborating second reading. Neither instrument can produce the other's evidence, which is what two observers was supposed to mean and was not. The entry deliberately refuses rather than falling back to its hostname when the label is absent: the fallback IS the defect, so an arm that restores it under a missing variable would re-open the hole in the failure path. Also the ci_spec target note still said the entry takes the credential path as a single String argument. It takes none. Third stale claim of this shape on this branch; the rule they add up to is that a sentence naming a state is a claim to be re-measured, not description. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * Prose in a carrier no fold reads is dead data, not a frontier Review 61775. host_reset_return_executed_receipt_frontier was a NonEmptyStr whose only content was the §3c frontier paragraph -- nothing imported it and no fold read it. §4c: an ordinary String declaration whose sole purpose is commentary is misplaced or dead data. §3c: a data row no fold reads is the dangling state, and the same trigger was already stated in the annotation directly above it, so the row was a second unconsumed authority for one fact. Dropped, annotation kept. Deliberately NOT re-homed as a DissolutionCondition: nothing folds frontiers today, so minting one here would move the same dangling declaration into a better-looking type and satisfy the letter of the finding while leaving its substance exactly where it was. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * The refusal receipt discarded the typed cause three claims said it carried review 61786: `reset_return_verdict` computes a `ResetReturnRefusalCause`, and the only production serialization path then dropped it — the receipt line said `verdict=refused` and nothing else, while the annotation, the exit reason, and the upload step that exists to make refusals readable all claimed the cause was there. A reader of the artifact could not tell an observer-is-subject refusal from an out-of-band issuance from a controller refusal, which are three different remedies. `reset_return_refusal_cause_wire` and `reset_observer_refusal_cause_wire` render one arm per cause; the pairing arm carries its inner cause through rather than flattening it. Both the receipt line and the exit reason now render it. Three witnesses discriminate ARMS — that no two causes render the same string, and that a pairing refusal's inner cause survives — rather than checking the string is non-empty, which would have been green on a constant. Also: five annotations sat inside `fleet_converge_host_reset_return_step`'s body, which the corpus parse phase refuses at module-item grain (the resolve path my local runs take does not reach that check). Hoisted above the declaration, and the workflow projection regenerated from the fixed authority — the drift the `heal-generated-artifacts` job reported at a715229. 46/46 witnesses PASS locally. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * Two annotations claimed more than the code does review 61814, both findings verified and both correct. `gunbc_ci_host_reset_return_target`'s annotation said the credential "arrives as a path by the same route" as the observer label. It does not. `git grep -n GUNBC_HOST_RESET_BMC_CREDENTIAL_FILE` returns exactly one module -- the entry that reads it -- and no step in `fleet_converge_host_reset_return_job` materializes it, so the emitted mode can today only reach the first refusal arm. That is the class this PR has now corrected three times: an annotation asserting a route as landed, which DESIGN section 4c says is never evidence a machine claim holds. The clause now states the frontier instead, names the Spark prelude whose shape the materialization will take, and says why the step is not written here: the secret resource name is an operator fact, and inventing a plausible one would emit a step that fetches nothing and writes an empty file -- a worse state than the honest refusal, because the file would then exist. The second finding: the two-paragraph block describing the CROSS PRODUCT was a verbatim duplicate sitting on `reset_observer_selections_for`, which is the PER-SUBJECT selection. One paragraph, two homes, one of them the wrong function. Removed the copy; the `NoPeerAvailable` rationale that genuinely belongs to that fold stays. While fixing the first item I wrote two citations to symbols that do not exist and caught them by grep before committing, which is the same defect one layer down. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * A refused pairing did not stop the power cycle review 61872, both findings verified, and the first is the most serious defect this lane has had. A REFUSED PAIRING FELL THROUGH TO THE CONTROLLER WRITE. `host_reset_return_attempt` computed the selection, then gated only on the identity, so an `ObserverSelectionRefused` -- `ObserverIsSubject`, `SubjectNotRostered`, `ObserverNotRostered`, `NoPeerAvailable` -- reached `oob_boot_handoff` and power-cycled the machine, after which the receipt rendered `pairing-not-minted` ABOUT A RUN THAT HAD ALREADY WRITTEN TO A CONTROLLER. The selection is the arm carrying `ObserverIsSubject`, so the wall this module advertises against resetting your own host was sitting BEHIND the write it exists to prevent. It was unreachable today only because `subject_for_observer` pre-filters -- safety coming from the caller, not from the arm the module presents as the wall, and the next caller does not inherit it. This is the same distinction the module already states for the identity check and did not apply to the selection. ONE AUTHORITY FOR "MAY THIS RUN WRITE". The second finding: the gate returned a Bool over ObserverSelfIdentity while `reset_return_verdict` independently matched the same coproduct to per-arm causes. One fact, two authorities, and the Bool was the lossy one -- it knew an arm was fatal but not why, so the caller invented a sentence the verdict already owned. `observer_identity_permits_issuance` is dissolved into `observer_identity_issuance_block`, which returns the refusal cause itself; the verdict now reads that classifier instead of re-deriving it, and `reset_issuance_block` composes selection-then-identity for the gate. Evidence: `every_selection_refusal_blocks_issuance_before_any_controller_write` covers all four selection causes; `an_admitted_pairing_with_a_distinct_identity_is_the_only_unblocked_shape` is the discriminator, since a gate that blocked everything would pass the first; `the_issuance_block_and_the_verdict_name_the_same_identity_cause` holds the two readings identical. Discriminating red measured: routing the refused-selection arm back through the identity check alone turns the first witness FAIL, restoring turns it PASS. Also, three witnesses in workflow_dispatch_input_witness_test that main's floor flagged and that ARE mine: the jobs list is an ordered exact partition and I inserted host-reset-return third, and the mode vocabulary count moved to sixteen. Pinned the new job with its `needs: [build]` edge -- it power-cycles its subject, so a stale binary there would drive real hardware from a model nobody reviewed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * A witness answering two questions could not finish either The floor on a5f2768 refused with one blocker of mine, and the log names the mechanism exactly: INTERRUPTED-BEFORE-VERDICT test.claim.workflow_dispatch_input_witness.fleet_converge_org_actions_mode_binds_secret_and_modeled_entry_holds raised_by=cpu_deadline cpu_at_least=501ms/500ms wall_at_least=503ms/8000ms That witness is enrolled cost debt and normally WITHHELD; because this branch edits the file it executes for its verdict, and it was interrupted one millisecond over the line, so it produced no verdict at all. THE DEFECT IS TWO SUBJECTS IN ONE WITNESS, and the cost is the consequence. Seven conjuncts ask about the org-actions INVOKE STRING; the eighth asked whether the whole emitted workflow carries a repository secret, which made the witness emit all 64KB of YAML to answer a question the other seven do not need. Adding a job to the workflow grew that emission enough to cross the line. Split on the subject boundary: the workflow-wide claim is now `the_fleet_converge_workflow_carries_no_org_admin_repository_secret`. Widening the 500ms line to fit a witness answering two questions would have been the wrong direction -- the roster was asking for this split, not for more budget. Separately, `fleet_converge_apply_step_binds_plan_hash_to_env_not_shell_literal` emitted the entire workflow TWICE for two conjuncts about the same rendered text. Bound once. That is not a cache: both demands share the witness frame as their least common ancestor, so this is removing an authored duplicate. All three PASS locally. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * The watch paced itself with a string on the line upstream had marked for retirement review 61938, verified and correct. The watch slept via `sleep.Delay.Seconds(seconds: "1" as NonEmptyStr)` -- a flat scalar naming a domain unit where std.measure already carries one. What makes it more than a style point is that extdeps.tools.sleep does not merely OFFER the carrier: it declares the flat-scalar form's own dissolution binding, `sleep_delay_seconds_flat_scalar_dissolution_trigger: Disposition = Scaffold { bind: ... sleep_delay_seconds_second_carrier_projection }`. So the call I wrote was minting a fresh spelling of a concept that already has an authority, on the exact construction the upstream module had marked for retirement. DESIGN section 2: net concepts must not grow by re-invention; section 3: each fact lives in one place. gunbc.live_deploy.readiness is the consuming precedent, and I agree with the review that the one sibling doing the same thing is evidence of debt rather than precedent -- the projection landed after it. Paced through the carrier, with the duration modelled as `host_reset_watch_sample_cadence: Second = second(count: 1)` beside the watch bounds rather than inline. That placement is the second half of the repair: the sample counts are DERIVED from the emitted step budget by multiplying by this cadence, and while the cadence was a string at the call site that arithmetic was carried in prose with nothing tying the two together. Witnesses re-run across the change: PASS. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * An unnamed observer queued a runner that does not exist review 61950, verified and correct. reset_observer is required:false because it is meaningful for exactly one mode, and its value is interpolated into the reset job's runs-on. A dispatch of mode=host_reset_return omitting it -- which an API or `gh workflow run` dispatch does by supplying "" -- passes the job's if: gate and asks for labels ["self-hosted","linux","arm64",""]. No runner carries an empty label, so the job QUEUES until the 105-minute backstop and dies with no diagnostic, no receipt and no upload; the upload step never runs, so not even its if-no-files-found: error fires. A silent stall standing exactly where the rest of this mode puts a loud refusal, and the one pairing state reachable at dispatch time was the one that neither refused nor ran. THE REFUSAL CANNOT LIVE IN THE RESET JOB, whose runs-on is resolved before any of its steps exist -- a step there is unreachable in precisely the state it would diagnose. It lives in `build`: generic labels, always schedulable, and needed by every host-scoped job, so the line stops before anything is scheduled rather than after something has queued. NOT A DEFAULT, which was the review's other arm. Defaulting the observer makes an omitted field silently select a machine and POWER-CYCLE ITS PAIRED SUBJECT. A default is right for a preference and wrong for an effect nobody asked for: the dispatcher who omits the field has not chosen a subject, and inventing one is the fabricated-plausible-output arm of section 5, not a convenience. Refusing costs a re-dispatch; defaulting costs a reboot. Evidence: `an_unnamed_reset_observer_refuses_in_the_always_schedulable_job` checks BOTH conjuncts of the guard, because one firing on the mode alone would refuse every correct reset dispatch and one testing emptiness alone would refuse every other mode -- either would satisfy a witness that only looked for the error string. `the_build_job_carries_the_reset_observer_dispatch_admission` holds that the step is actually in the job, since a step function nothing calls is the dangling-declaration shape and would pass its own witness while never running. Discriminating red measured: dropping the mode conjunct turns the first FAIL. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * The backstop derives the job it guards; and my split doubled a 500ms render review 61958, both findings verified and correct. THE BACKSTOP NO LONGER DERIVED THE JOB IT GUARDS. It was a hand-kept sum of per-step budgets, and this branch inserted a fourth step into the build job with its own 5-minute budget without adding a term -- so the job backstop could fire while every step was still inside its declared budget, and it would have read as a hung build rather than as a miscount. Rather than add the missing term, the sum now FOLDS the step list: fleet_converge_build_job_steps() is bound once and consumed by both the job's `steps:` and the backstop, so adding a step and adding its budget are the same act and the two cannot disagree. Construction where a check would have been the alternative; emitted backstop moves 65 -> 70. THE HAND-SHELL GATE CARRIED NO SCAFFOLD MARKER. The dispatch-admission step is a concat-built program handed to a foreign executor's `run:`, which is exactly the shape gunbc.ci_spec ci_release_bins_pack_shell_emit_dissolution_trigger names, and DESIGN section 6 is explicit that a MISSING dissolution condition makes the finding more severe rather than less. Added fleet_converge_reset_observer_admission_shell_emit_dissolution_trigger, following the sibling's form including emitting the description into the script as a comment, and naming the same trigger (bash-emit, #5828 / shell->intent Phase 2). AND A COST FINDING OF MY OWN, from CI on ae71183 rather than the review: BOTH witnesses I added in the previous commit were interrupted before verdict at 507ms and 509ms against the 500ms line. The measurement says rendering this workflow -- or constructing its five jobs -- is roughly the entire claim budget by itself, so splitting the org-admin-secret claim into its own identity was right on SUBJECT and wrong on COST: it rendered the workflow a second time for one extra string test. Both repaired at the mechanism rather than by budget: - the build-job witness folds fleet_converge_build_job_steps(), the same single authority the job consumes, instead of indexing fleet_converge_workflow -- one job's steps instead of five jobs, same question answered. - the org-admin-secret claim moved into the witness that ALREADY renders the workflow, which now asserts both absences over one render. Two demands, one frame as their least common ancestor, so the first value is carried. Net renders in the file are unchanged at two; my additions now cost no render at all. Both PASS. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * The annotation still described the design review 61761 removed review 61989, verified and correct. The fleet-converge annotation and the PR body both said gunbc.host_reset_return_run "learns [the subject] from the machine it is running on." That is the collapsed form review 61761 already removed from the CODE, left standing in the prose beside it: the entry reads the CARRIED observer label out of the environment and refuses rather than falling back to its own hostname. WHY THIS IS NOT A WORDING SLIP. Keying the entry on `hostname -s` made the label that decided WHERE the job ran and the name the machine ANSWERS TO one reading, so a runner labelled srv1 but living on the subject chassis, or a host reporting "ubuntu" because it never converged, failed the assignment lookup as "not an assigned observer" and never reached the identity check at all -- leaving ObserverIsTheSubjectMachine and ObserverHostnameNotConverged reachable only from fixtures while the module cited them as the wall protecting the hardware. One fact with two incompatible spellings is DESIGN section 3's meaning fork, and here the stale spelling is the one a later worker would most plausibly act on, because it describes a simpler design. Acting on it would re-derive the subject from the machine and disarm the label-versus-hostname corroboration the hardware depends on. Corrected in the annotation and in the PR body, both pointing at the argument in gunbc.host_reset_return above reset_return_verdict_of_mint rather than restating it a third time. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * A witness rename is a silent de-enrollment from the cost-debt roster CI on a2c6d6b, not a review. My previous commit merged two workflow-wide absence claims into one witness to stop rendering the workflow twice -- right on cost -- and RENAMED the witness while doing it, which was wrong on identity and produced both halves of the failure: INTERRUPTED-BEFORE-VERDICT ...the_rendered_workflow_carries_neither_a_pasted_heal_sha_nor_an_org_admin_secret raised_by=cpu_deadline cpu_at_least=523ms/500ms BLOCKING ...fleet_converge_workflow_has_no_heal_revalidation_paste_through is enrolled in v2.workflow.floor_cost_debt but the tree DECLARES NO SUCH IDENTITY WHAT I HAD WRONG ABOUT THE 500ms LINE, which is worth stating because I acted on the wrong model twice. It is not a budget these witnesses can meet: the floor reports marginal_cpu_ms of 1264, 1398 and 1399 for the siblings in this same file that construct or render the workflow, and they pass. It is the threshold above which a claim must be ENROLLED as declared cost debt, after which the line is observed and published rather than gating. So the fix was never to shave milliseconds -- the org-actions witness at 501ms and this one at 523ms were both telling me they had left an enrolled identity, not that they were slightly too slow. The enrollment is keyed by fully qualified witness name, so a rename silently de-enrolls. Name restored; the merged conjunct rides along on the enrolled identity, and the annotation now says the name is load-bearing so the next reader does not tidy it. The two identities this branch genuinely adds stay unenrolled on purpose: both were built to touch one step and one step list rather than the workflow, and the a2c6d6b run confirms they complete inside the line. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * The run_id field carried a sentence instead of the run review 61998, verified and correct, and it is mine twice over: I wrote that string, and I wrote the annotation defending it. The only production ResetIssuanceRoute carried run_id: "unbound: the run identifier is not read by this entry; the uploading run is the binding" so every real receipt this mode would ever mint carried prose in a field whose type says it names the run that issued a power cycle. That is section 4c's misplaced data in the one field a reader needs to get from the artifact back to the run that drove the machine. THE ANNOTATION ARGUED AGAINST A CHOICE NOBODY OFFERED. It defended the sentence on the grounds that an interpolation-shaped literal would render as a real-looking identifier naming no run -- true, and irrelevant, because the modeled reading already exists: extdeps.github.actions_environment github_run_id_variable_name models the variable, gunbc.actions_run_binding actions_variable_read performs the read with an absent-versus-set-but-empty distinction, and this very step already proves the env route works because it hands the observer label over the same way. I had hit the interpolation parse error early, concluded the reading was unavailable, and never revisited it once the env route was built. AN UNIDENTIFIED RUN NOW REFUSES BEFORE ISSUANCE. run_id is mandatory and there is no honest value for it, so the read is its own outcome: ResetIssuanceRouteRead is RouteEstablished or RouteUnidentified, and the entry exits on the second before any controller write. An optional field was the other arm and is worse: it would let the power cycle proceed and mint a receipt that cannot support the one claim this carrier exists to make -- that the reset was unattended and went through converge. A receipt no reader can trace to its run does not establish that, so the gap has to stop the line rather than be recorded after it. Same ordering as the observer-identity and pairing walls, for the same reason. No witness added for the unidentified arm: with run_id mandatory and the read returning a coproduct, there is no way to author a RouteUnidentified that yields a route, so a check would be permanently green by construction -- section 4b's decoration, worse than absent because it would be cited as coverage. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * The refusal the upload step exists to carry was never written review 62016, verified and correct. Five arms refuse before any pairing is minted -- no credential path, no observer label, an unidentified run, an observer the assignment does not place, a subject with no roster row -- and every one of them exited without touching host_reset_return_receipt_path. The only write was inside host_reset_return_exit, which those arms never reach. Meanwhile the upload step runs `if: always()` with `if-no-files-found: error`, and its own annotation states the property: "THE RECEIPT IS UPLOADED ON FAILURE TOO ... the refused case is the one somebody needs to read, and an upload conditioned on success discards the evidence exactly then." So on every refusal this mode can actually reach today, the artifact did not exist and the run's final red named the MISSING FILE rather than the missing credential -- the located diagnostic displaced by an artifact-plumbing error. A claim in the carrier the code did not hold, which is the shape this branch has now caught in itself four times. THE PREFLIGHT CAUSES ARE THEIR OWN VOCABULARY, not new ResetReturnRefusalCause arms. That type answers for an attempt that was MINTED: each of its causes presupposes a pairing, a route and an observation. A preflight refusal has none of those, and widening the verdict type with causes reset_return_verdict can never produce would leave those match arms unreachable while reading as coverage -- the same defect review 61829 found in this module, deliberately not repeated. attempt=none-minted is the honest field rather than a placeholder: there is no attempt label and no subject to name at that point, and writing "unknown" would put a row in the receipt claiming a subject a reader could sort on. Evidence: w_preflight_refusals_do_not_collapse_into_one_another holds all five pairwise distinct, since an operator has to tell an unnamed observer from an unidentified run and they are different remedies at different layers; w_a_preflight_refusal_names_the_variable_or_host_it_is_about holds that each carries the variable or host to act on, which a class-only wire would not. Discriminating red measured: collapsing one arm to a constant turns the second witness FAIL, restoring turns it PASS. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * The job that reboots a machine belonged to no mutation domain review 62030, verified and correct, and it is the most consequential finding on this branch after the refused-pairing one. fleet_converge_host_reset_return_job() landed with concurrency: none while being the most mutating job in the workflow -- it power-cycles a physical host. Every other host-touching job carries fleet_host_mutation_concurrency_group_expression, whose own annotation states the rule and gives this mode's exact subject as the reason: ONE MUTATION DOMAIN PER HOST, SHARED BY EVERY JOB THAT CONVERGES OR READS BACK THAT HOST (RLM-2 ruling section 9), because a readback can otherwise observe another transaction's mutation. A section 3b divergence in the leasing/locking domain with nothing anywhere stating a reason, which is the only red that section admits. THE FABRICATION IT ADMITTED IS THE ONE THIS MODULE EXISTS TO REFUSE. Two dispatches naming DIFFERENT observers resolve to the SAME subject; B's power cycle lands inside A's watch window and A mints HostObservedDownThenBack for a return it did not cause. The pre-issuance baseline cannot catch it, because B issues while the subject is still up during A's handoff -- so it arrives by the one route SubjectNotUpBeforeIssuance is blind to, and the receipt carries a measured downtime for someone else's reboot. Every wall in this module aims at that class and the workflow left the door open beside them. THE GROUP KEYS ON THE SUBJECT, WHICH THE DISPATCH DOES NOT CARRY. The observer-to-subject map is emitted from the same assignment the option list comes from and indexed by the dispatch input, so it is derived rather than spelled: a pairing the mint refused cannot appear in it, and an unmapped observer yields an empty subject that cannot collide with a real host's domain. Emitted group resolves to gunbc-host-mutation-mtcollins1 -- the same domain a mode=apply against that host takes. WHAT IS NOT COVERED, AND SAYING SO IS THE POINT. GitHub admits one group per job and this job needs two domains: the subject's, and the observer's, since an apply naming the observer can reboot the watcher mid-watch. The subject's is taken because a fabricated down-then-back is a WRONG receipt while a rebooted observer is a LOST one -- that failure is loud, this one would not have been. The residual is not closable here; its trigger is already named in fleet_workflow_steps, which records that the host lease exists, is witnessed, and is not yet acquired by this workflow. A lease holds two hosts where a group holds one. Evidence: the_reset_job_shares_the_mutation_domain_of_its_subject, whose last conjunct is the discriminating one -- a group keyed on the OBSERVER would satisfy "has a group" while admitting exactly the collision, since the observers differ and the subject does not. Discriminating red measured: replacing the derived expression with the observer-keyed one turns it FAIL. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * Two failure-mode rows, both filed as records rather than repairs The classes this lane produced, filed separately because they have different recognition rules and folding them would give one row two. declared_refusal_unreachable_from_its_own_constructor: a refusal arm whose only constructor implies the state that makes the arm unreachable. Three instances in gunbc#10739 alone -- NoPeerAvailable never constructed because the fold mapped over an empty roster and contributed zero selections rather than one refusal; the observer-identity arms fixture-only because the entry keyed on `hostname -s` and failed the assignment lookup first; and SubjectWasNotUpBeforeIssuance, the purest form, where the precondition and the shadowing state are the SAME FACT, so care at the construction site cannot help. Ceiling is mechanically preventable: arm reachability from a named entry is decidable over the Node tree the namespace authority already reads. enforcement_gate_positioned_after_the_effect_it_guards: a refusal computed before the effect and enforced after it. Two instances -- the identity check that power-cycled the machine the job was standing on and then reported the refusal, and, after that repair, a refused PAIRING still falling through to the controller write. The second is the instructive one: its arm was unreachable only because a CALLER pre-filtered, so the module presented as its wall an arm whose safety came from somewhere else. Ceiling is structurally guaranteed -- the effect can require the guard's permitting value as an argument, so an unpermitted call has no form. BOTH ROWS STATE THAT NOTHING IS NOW HARDER TO DO THAN BEFORE. They are records, not repairs; both classes stand UNREMEDIED at mitigatable and may not be cited as coverage. That is a_written_row_is_not_a_firing_mechanism's obligation, and it applies to these two as much as to any others -- discharging it by saying so plainly rather than by implying a climb. Each carries a next-rung trigger naming a CAPABILITY (an arm-reachability reader; an effect-ordering reader) with what it must be sufficient for, not an artifact that would contribute to one. The interim practice that did fire, offered as practice and not as mechanism: mutate the guard and re-run the witness. A fixture-shaped witness stays green under `if false`; every repair in that lane was confirmed by a measured red there. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * chore: regenerate drifted generated artifacts (ci auto-heal) Ledger-Repair-Judged: docs/design-failure-modes.md Ledger-Rows-Repaired: docs/design-failure-modes.md declared_refusal_unreachable_from_its_own_constructor Ledger-Rows-Repaired: docs/design-failure-modes.md enforcement_gate_positioned_after_the_effect_it_guards Ledger-Repair-Judged: docs/design-rung-drops.md * The concurrency-group map was hand-built JSON, one function from the gate that class exists to close review 62097, verified and correct. fleet_converge_reset_subject_map_json built its object from string literals and fed it to fromJSON, while extdeps.languages.json.emit already carries json_object, json_kv, json_string and serialize_json -- and this module already consumes the YAML sibling, so reaching for the JSON one is the same move rather than a new dependency. Section 2: net concepts must not grow by re-invention. THE FAILURE IT REMOVES IS THE ONE THIS WORKFLOW ALREADY LEARNED. Nothing in NonEmptyStr or HostIdentity forbids a label carrying a quote or a backslash; escaping was unmodeled, so such a label emitted malformed JSON, fromJSON failed at JOB-SETUP time before any step existed, and the reset job died with no receipt and no upload. That is the silent-stall class the dispatch-admission gate was added to close in this same file, reintroduced one function away from it by the fix for the concurrency finding. serialize_json escapes through escape_json_string, so the emitter owns that fact and nothing here restates it. THE FOLD NOW TAKES ITS PAIRINGS AS AN ARGUMENT, and that is the load-bearing half rather than a tidy-up. Reading the assignment data row directly, the only witness available would have restated what the emitter does and been green by construction -- section 4b's decoration, worse than absent because it gets cited as coverage. Split so a hostile label can be handed in: a_reset_subject_map_escapes_a_label_that_would_break_the_json mints a pairing whose observer carries a quote and holds that the rendering escapes it and does not contain the raw broken form. Discriminating red measured: restoring the concat body turns that witness FAIL. The emitted workflow is byte-identical, which is the expected result -- today's labels need no escaping, so this is behaviour-preserving for current data and differs only where the old form was wrong. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * Rebuild the dispatch gate modeled; the scaffold bought nothing The onboarding re-read against docs/plans/scaffold-admission-doctrine.md found a defect in my own head, and it is one that survives being green and approved. fleet_converge_reset_observer_admission_shell_emit_dissolution_trigger was a NET-NEW ACTIVE dissolution obligation with no operator verdict on that population, which the doctrine calls a hard reject: marked-but-unapproved debt is refused. The api-review APPROVE does not cover it -- approval is external to the diff precisely because an author who can write a scaffold can equally write a row claiming it was approved -- and review 62127 reasoned that the marker "meets the wall as stated", which answers the LIFECYCLE question (how would this disappear) and not the ADMISSION one (may it exist at all). The doctrine separates those deliberately and I had answered only the first. THE DOCTRINE DECIDED IT WITHOUT A JUDGEMENT CALL: the default landing state is the final construction, a scaffold is an approved EXCEPTION reached for when the construction is unavailable, and here it was available. So the scaffold's whole benefit was saving ONE BUILD on a dispatch that was already wrong, against authoring, review, maintenance, deletion and review of the deletion. WHAT REPLACED IT. gunbc.host_reset_return admit_reset_dispatch is a three-arm fold over the two dispatch inputs, and host_reset_return_dispatch_admission_wet is the entry the build job invokes through the ordinary gunbc run step, taking both values by environment. The gate moved AFTER the release build because it needs the binary; the safety property is unchanged, since the reset job needs `build` either way and is never scheduled in the state this refuses. IT REFUSES WITH A CAUSE RATHER THAN SKIPPING, which the parent flagged before I built it: a gate that silently declines to run reads as a pass to anyone looking at the job list, so the not-this-mode arm exits successfully and SAYS SO, and the unnamed-observer arm exits non-zero with the located diagnostic. Evidence, now over ARMS rather than over rendered shell text: the admission witness holds all three arms, its last two conjuncts discriminating -- a gate refusing on the mode alone would reject every correct reset dispatch, one ignoring the mode would reject every other mode. A new witness holds that a whitespace-only observer is unnamed too, which the shell `-z` caught for free and a modeled comparison does not unless it trims. Discriminating red measured: making the fold mode-blind turns the admission witness FAIL. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe * The Bool over a coproduct came back one function later review 62169, verified and correct, and the sharp part is that this module had already made this exact correction. subject_was_down_before_issuance was a Bool over HostReturnObservation: one arm true, every other arm false. That re-encodes a variant test the sum already carries and then throws away what it learned, so the caller minted SubjectWasNotUpBeforeIssuance a second time -- one fact with two authorities. It is the same shape as observer_identity_permits_issuance, which review 61872 had me dissolve into observer_identity_issuance_block returning the cause itself. I applied that lesson to the identity wall and reintroduced the shape at the already-down wall in the very next commit. observation_issuance_block now returns ResetReturnRefusalCause?, the verdict binds the cause it is given rather than re-minting one, and the Bool is deleted with no marker: there is no debt to mark, the construction was simply available. Witnesses unchanged and passing -- the already-down witness, its not-attempted discriminator, and the down-then-back positive control. The discriminating red still bites at the new shape: making the block never fire turns w_a_subject_already_down_at_issuance_refuses_on_its_own_cause FAIL. Worth recording because it is the second instance and the roster now carries the class: a repair applied at one site is not applied at its siblings unless somebody looks for them. The identity fix and this one were one commit apart, in the same file, with the same reviewer-supplied reasoning in front of me. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QiMCBr1aMNXBza2BWJHaRe --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
…edown script carries its bash-emit marker (review 70414) plan_jit_mint and dispatch_jit_mint take a MicrovmRunnerGroupStanding instead of a bare id; RunnerGroupRestrictionUnobserved refuses (JitMintRefusedRunnerGroupUnrestricted -> DispatchRefusedRunnerGroupUnrestricted). The slot controller passes the unobserved arm, so the block microvm_jit_runner_group_restriction_frontier states is now the match itself. New red witness: an otherwise-authorized mint refuses on it. microvm_shakedown_known_task_script gains its dissolution row naming bash-emit (#5828), rendered as the script's first line like its ci_spec siblings. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ssible on the bash_build node route today Review on bf218e3: C1 turned an AVAILABLE emission route into a missing prerequisite. v2.extdeps.languages.bash_build nodes emitted by v2.workflow.bash_emit bash_emit_stmts already carry typed quoted words, command substitution, assignment, pipe, if/test, redirect and || true; set/umask/export/trap are ordinary commands on it (#12422 retired the pack runner that way). The 11 runner rows and the fci1/tools headers now say the migration is unauthored, not blocked. C5 (background job), C6 (POSIX sh dialect) and C7 (transport argv is a service-declaration literal) remain the genuine gaps. The pack row is restored to main so #12422's deletion lands cleanly. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…host effect via the bash emitter (#5828) (review 72000) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…d hold/step scope with #12430's capability names ([C5 background-hold]; the bash_build route for the credential runner); regenerate Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Auto-opened by session-dashboard for session
fierce-crane-753.Pushing to
session/orchestration-bash-coverageadvances this PR.Worker attestation
Before flipping this PR to ready for review, confirm each item:
npm test,cargo test) and the result.Closes #Ndirective.Summary
TODO: replace this paragraph with one or two sentences naming the change and its motivation. Reviewers read this first.
Test plan