Repository navigation
Apply the host-wide executor grants from the converge spine, and read the kvm grant back - #11765
Conversation
… the kvm grant back /dev/kvm membership for the runner executor was AUTHORIZED and never APPLIED: gunbc.runner_host_grants emits EnsureSupplementaryGroupMembership and runner_host_sudoers_content renders permission to run its argv, while gunbc.runner_microvm_host_ready disclaimed it — granted by one module, disclaimed by another, executed by neither. srv2 became writable on 2026-09-05 because an operator typed the rendered argv by hand, which is the rostered class gunbc.recurring_failure_mode capability_arrives_outside_the_converged_path. The applier is wired from gunbc.fleet.fleet_converge_plan and NOT from the disclaiming module, which is that row's explicit ruling: an apply reached outside the spine inherits none of fleet_converge_plan_held_lease. host_wide_grant_apply_lines emits runner_host_wide_refused_operations into the full-host apply script beside the fabric-cell effects, rendered through executor_privileged_operation_converge_command — the same value the sudoers line is rendered from — so the grants run under the generation flock with every other host mutation and an operator reads them in plan.txt first. They resolve through runner_host_spec_for rather than runner_host_deploy_for, so a rostered host whose width refuses still gets the grants its own sudoers authorizes. The readback stays with the module that CLAIMS the capability. A supplementary group enters a process's credentials at exec, so the converge that applies the grant still reads present-not-writable; a test -w readback would refuse a host that had just converged. The standing now carries KvmGroupEnrolment, read from the account database with id -nG <login>, and readiness splits: firecracker_host_ready admits enrolment (the converge's question, effective at the next incarnation) and firecracker_host_ready_in_this_process requires writability (the boot probe's question, because it opens the device itself). The receipt states the grant is effective for incarnations started AFTER it, so present-not-writable beside enrolled is not read as a reason to restart a live slot. Evidence: 7 claims in runner_microvm_host_ready_witness and 2 in fleet_converge_plan_witness, all PASS under claim_batch; the enrolment claim is the discriminating one (it reds if readiness requires this process to open the device), and the plan claim asserts the exact elevated argv plus a non-rostered host contributing no usermod line. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…does not carry The relocation note in runner_microvm_host_ready pointed a reader at `fleet_converge_host_wide_grant_lines`, which resolves nowhere. The emitter this PR adds is `gunbc.fleet.fleet_converge_plan host_wide_grant_apply_lines`. Caught by review 68771; it is the one citation in the module that points at the relocated applier, so a reader following it found nothing. DESIGN section 3: name the module and symbol, and a stale name is decidable because the namespace authority reads the same Node tree. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Fixed in ba2479a. review 68771 is right: the relocation note named — sent from wise-wren-164 |
…top the header understating the fold Three findings from the side-chat hold on #11765, all real. (1) kvm_reachable short-circuited on KvmDeviceWritable, which answers a question about the NEXT incarnation from the CURRENT one. A process that inherited the kvm group before the grant was revoked still holds an open path to the device, so the host read ready while the login was no longer enrolled at all — and the next incarnation, the one the whole split exists to speak for, would fail. Converge readiness is now answered entirely from durable host state: the device exists AND the host delegates it to the modeled group AND the account database enrols the login AND firecracker is installed. A writable device is evidence for firecracker_host_ready_in_this_process and nothing else. Both writable-but- ungranted shapes are discriminated — writable plus not-enrolled, and writable plus enrolment-unreadable — each false for converge and true in-process. (2) Enrolment plus presence did not prove the next incarnation can open the device: present-not-writable plus enrolled has a second explanation, that /dev/kvm is not delegated to group kvm with group-write on this host. Ubuntu's udev default is upstream DESIRED STATE, not a readback, and reading a capability off it is asserting as deduced what was only inferred (DESIGN §4d). KvmDeviceDelegation now observes it — Delegated / Contradicted{expected, observed, group_writable} / Unreadable — and converge readiness requires it. The observation joins the device's group name and its group-write bit through extdeps.tools.coreutils_stat, whose new PathMode operation fetches %a; what those digits MEAN stays with extdeps.access.posix, which gains file_mode_of_octal_text as the declared inverse of file_mode_octal (DESIGN §4: one grammar, two directions) rather than a parser authored beside the consumer. (3) The full-host apply printed "# runner-slot membership — ADD only" immediately above a fold that can emit systemctl mask --now for an authorized surplus unit and remove a retired tree. The inner headers named both honestly; the OUTER one — the line an operator reads before approving a host mutation — claimed a narrower blast radius than the script carries. It now names additions, retirement inhibition via mask --now for units the retirement admission authorized as surplus, and removal only for a unit with an independently reobserved RetirementComplete, and states that no desired runner is stopped, restarted or reinstalled. Evidence: 9 claims PASS in runner_microvm_host_ready_witness (including the two new discriminators above) and 3 in managed_directory_witness for the octal inverse, under claim_batch. fleet_converge_plan_witness could not be resolved locally — refused twice with MemoryStallRefusedPageThrash on a host at 99/125 GiB, which is cannot-tell rather than red — so its two claims, including the new header claim, are executed by the required witnesses lane. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
All three side-chat findings are fixed in 8142469. Each was real; taking them in order. (1) (2) Enrolment plus presence did not prove the next incarnation can open the device. Took the delegation observation rather than the rename, because the rename would leave the standing unable to tell the two explanations apart. (3) The header. Confirmed your reading of the fold before touching it: Evidence: 9 claims PASS in — sent from wise-wren-164 |
# Conflicts: # dag/extdeps/tools/coreutils_stat.dag
Ledger-Repair-Judged: docs/design-rung-drops.md Ledger-Rows-Repaired: docs/design-rung-drops.md namespace_wave_admission_wall_removed Heal-Candidate-Run: 35487965261
|
The two The correction. I wrote that these two claims were deferred to "the required witnesses lane", and review 68883's closing note accepted that as "cannot-tell reported as cannot-tell — the lane is the wall". There is no such wall. On this head The run. Worktree Five earlier attempts were OOM-killed at ~10–12 GiB peak while the session host was contended; this one ran once the slice cleared. All 14 claims on this PR have now executed — none are deferred. — sent from wise-wren-164 |
# Conflicts: # docs/design-rung-drops.md
|
Correcting my earlier comment on this PR, which said "no PR check executes witness claims". That was true of the head it was written against and is not true as an absolute — but the accurate statement is worse, not better, so I am stating it rather than quietly dropping the point. (This replaces a mangled version of this comment: I passed the body through a double-quoted shell string and its backticks were executed, which ate several of the values and spliced in a 404 blob. The figures below are the real ones.) A It also fails open. On run 35505868144, job 106065468152 (head …while the API reports the job So the two readings are not in conflict: the lane executes witnesses when nothing refuses, and does not fail the step when something does. The gate is real on a clean head and absent exactly when something is wrong — which is the worse of the two shapes, and is §5's "a failure arm must refuse, never widen" inverted onto the gate itself. A green One method note, since it nearly cost me the finding: my first This does not change the evidence position for this PR: all 14 claims here were executed locally and reported with their run output, not deferred to any lane. — sent from wise-wren-164 |
|
Re-ran every claim on this PR with a binary of known provenance, because the earlier greens had none. A sibling lane (keen-bear-791) retracted a 45/45 after finding it had run Applying that to my own receipts, they failed:
So I withdrew both and rebuilt from my own head into a private Provenance — identical for both binaries:
Results, both unchanged:
The verdicts did not move. What changed is that they are now worth something: a witness verdict is only as current as the binary that produced it, and on a shared target directory reaching a stale one is the default rather than the exception. — sent from wise-wren-164 |
…e understating the script Two source blockers from the side-chat hold on #11765. BLOCKER 1 — the converge certified a host it never bound. Resolving the kernel hostname stops srv1's SPEC being applied to srv3; it does not stop srv3 being converged and certified under srv1's name, because the run's concurrency group is keyed to the host the operator REQUESTED. A mutable scheduling label is routing evidence, not machine identity (the subject-binding rule of gunbc#11751). The dispatch's selection (FLEET_CONVERGE_EXPECTED_HOST) and the machine's own answer are now joined into a sealed MicrovmHostBinding, matched FIRST in both wet entries — outside the arm that reaches HOME, the fetch, the install and the receipt write — so a mismatch refuses having performed zero install operations. Four typed causes, because they send an operator to four different places: ExpectedHostAbsent, HostObservationFailed, HostBindingRefused{expected, observed}, HostNotRostered. The receipt now names the bound host and the bound login. At that same join, readiness VERIFIES rather than assumes. kvm_reachable matched the positive coproduct arms for their SHAPE and discarded the login and group they carry, so "device delegated to group A" beside "some login enrolled in group B" read as ready, and the login believed was whichever the observation was asked about rather than the one the bound roster row names. Three equalities are checked: enrolment.login == bound spec.job_user, and enrolment.group == delegation.group == kvm_device_group. BLOCKER 2 — the FIRST admission-gate scope line at the top of apply.sh still said "runner-slot ADD" above a fold that can also emit authorized mask --now retirement inhibition and completed-retirement tree removal. The later detailed header was repaired; this earlier rendering site was not, and the existing witness checks the family header so it could not see it. This is the original ADD-only defect at a second site. fleet_converge_apply_shell_axis_note now names all three dispositions. Evidence, with a binary of known provenance (built 2026-09-20 11:26:55 from 611088d, clean tree, private CARGO_TARGET_DIR): - a_host_that_is_not_the_dispatched_one_refuses_and_names_both — the required RED: expected=srv1, observed=srv3 refuses carrying BOTH names. PASS. - readiness_checks_the_carried_login_and_group_rather_than_their_shape — breaks each of the three equalities on its own, since a check that only fires when all three are wrong is satisfied by any one being enforced. PASS. - the_top_admission_gate_line_names_retirement_not_add_only — extracts THAT LINE and asserts over it alone, because a whole-script check is satisfied by the truthful header lower down. PASS, and VERIFIED DISCRIMINATING: reverting the wording to "runner-slot ADD" turns it RED, then restored. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ote moves above the service
The PathMode prose sat INSIDE the `service coreutils.Stat { ... }` body, indented.
Annotations are modeled at module-item grain only, so the parser refuses one inside a
declaration body: ten `source annotation sits inside a declaration body` errors, and the
whole projection regen refused with them.
Found only because the regen was re-run with a compiler built from this exact head. The
earlier binary did not enforce it and returned rc=0 over the same bytes, which is the
staleness hazard in miniature: the check that refuses my source is newer than the compiler
I was reading the result from. The prose is unchanged in substance and now describes
PathMode from above the service it belongs to.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…host, and the prose stops saying the grant is refused Review 69146 and review 69224, same root, and they are right: the binding I landed had no executing route. gunbc.runner_microvm_host_ready seals the operator's choice against the machine's own hostname before any fetch, install or receipt write, reading that choice from FLEET_CONVERGE_EXPECTED_HOST — and both steps that invoke it carried `env: none`, so `microvm_host_converge` and `microvm_boot_probe` would have exited ExpectedHostAbsent on EVERY dispatch. The readback this PR exists to deliver could not start. That is DESIGN §3c's consumption question answered in the negative, and §5's specification-without-execution: the witnesses supply the binding values, which is correct, but the real-path half was dead rather than merely unexercised. Both steps now set FLEET_CONVERGE_EXPECTED_HOST from github.event.inputs.host, the way every sibling entry that reads the variable already does, and the workflow is regenerated from its authority (rc=0) rather than hand-edited. Second surface, same root: the step's prose and the operator-facing mode description both still said this mode "refuses the kvm grant by name". That was true of the disclaiming version and is now false in the direction that matters — an operator reading it would not know the grant has an executor at all. Both now say the grant is applied by the full-host apply spine and READ BACK here, refusing by name when it has not landed. Control: both_microvm_steps_pass_the_selected_host_to_the_binding asserts over the STEP VALUES rather than the emitted YAML, because the text is a projection and the defect was in what the projection was given. Both modes are checked — they fail independently, so a control over one would have left the other dark. It is NOT in test.claim.workflow_dispatch_input_witness, the module that already imports these steps, because that module does not resolve at this head: a pre-existing `workflow_trigger_entry(trigger: fleet_converge_workflow.on[0])` now produces an Optional where a WorkflowTrigger is declared. A control placed there would be dark, which is the defect being repaired. Reported separately; not fixed here. Evidence at this head, exact-head binary (built 2026-09-20 14:51:29 from 21ea587, no src/ delta since): 4 PASS in fleet_converge_plan_witness including the new control, rc=0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Both findings are real and both are fixed in
Fix. Both steps now set Second surface, same root. The step prose and the operator-facing mode description both still said this mode "refuses the kvm grant by name" — true of the disclaiming version, and now false in the direction that matters: a reader would not know the grant has an executor at all. Both now say the grant is applied by the full-host apply spine and read back here, refusing by name when it has not landed. Control. One thing I did not fix, reported rather than silently worked around. The natural home for that control is Evidence at this head with the exact-head binary (built — sent from wise-wren-164 |
# Conflicts: # .github/workflows/fleet-converge.yml
|
Retracting one claim from my previous comment. I said
And the class was already rostered — I did not discover it. What stands from that comment: the claim lives in Current main is now composed ( — sent from wise-wren-164 |
The floor's generated-artifact drift gate failed at 1af9f21, and the cause was mine. Composing main conflicted in `.github/workflows/fleet-converge.yml` — a generated projection — so I took the base side verbatim to settle it, which is right for the merge and only half the operation: the AUTHORITY on my side carries `env: Present` with FLEET_CONVERGE_EXPECTED_HOST on both micro-VM steps, and the base-side projection does not. I verified the authority survived the merge, then never re-ran the regen, so the committed YAML drifted from the module it is derived from. That is exactly the hazard recorded against gunbc#11751 — "the last merge took one side of the YAML and regen was not re-run" — realized in my own tree, one commit after I wrote a note warning about it. Regenerated from the merged authority with `generated_artifact_gate` `main_wet_one` (rc=0), not hand-edited, and verified the binding landed: both `microvm_host_converge` and `microvm_boot_probe` now carry the env in the emitted YAML. Without this the route repair was present in the source and absent from the thing GitHub actually runs, which is the same defect the reviews caught, reintroduced by a merge rather than by an edit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ge and regenerate Same two paths as the previous merge and the same resolution, because they are the program's shared spine: #11765 and #11679 are sibling microVM lanes editing fleet_converge_workflow.dag, so every lane in this program serializes on this file and its generated projection. Roster is the union at 32 modes -- this branch's MicrovmNetworkObserve beside main's MicrovmControllerAppKeyConverge -- with the type arms, the roster and fleet_converge_mode_scope checked to agree exactly. The workflow YAML is regenerated from the merged sources and carries both. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three §4c body annotations hoisted to module-item grain (host_capture_historical_binding, runner_microvm_boot_probe, mtcollins1_census_image_local_wet_test), and floor_route_gap chunk_20's seven 'tail:' fields whose value sat on the next line -- a parse refusal that orphaned every annotation in the file -- joined onto one line like every other chunk. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…t_capture_historical_binding and runner_microvm_boot_probe to module grain (they refuse to parse and red every floor run) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
What was wrong
/dev/kvmmembership for the runner executor was authorized and never applied.gunbc.runner_host_grantsrunner_host_wide_refused_operationsemitsEnsureSupplementaryGroupMembership{job_user, kvm},runner_host_sudoers_contentrenders PERMISSION to run its argv, andgunbc.runner_microvm_host_readyexplicitly disclaimed applying it — granted by one module, disclaimed by another, executed by neither. srv2 readskvm=writableonly because an operator typed the rendered argv by hand on 2026-09-05; srv1 readspresent-not-writable, so its micro-VM boot probe cannot reach an image verdict. That is the rostered classgunbc.recurring_failure_modecapability_arrives_outside_the_converged_path.Where the applier went, and why not where the brief said
My brief said to wire the applier into the
microvm_host_convergemode. The rostered class forbids exactly that, by module name: "A lane wired the existing applier fromgunbc.runner_microvm_host_ready— the disclaiming module — as its own CI run step, which is exactly the arm this ruling forbids" … "NOT an applier bolted beside the disclaiming module." Its reason is substantive: an apply reached outside the spine inherits none offleet_converge_plan_held_lease, so two applies against one baseline could both proceed. I escalated; the operator ruled for the spine and corrected the brief.So
gunbc.fleet.fleet_converge_planhost_wide_grant_apply_linesemitsrunner_host_wide_refused_operationsinto the full-host apply script, beside the fabric-cell effects, rendered throughexecutor_privileged_operation_converge_command— the same value the sudoers line is rendered from, so what is permitted and what is executed cannot drift into two spellings. The grants therefore run under the generation flock with every other host mutation. Correction: an earlier version of this description said an operator reads each argv inplan.txt. That is wrong — the grant argv is emitted intoapply.sh, and the witness asserts againstartifact.apply_shell; nothing here establishes it as a line inplan.txt. PLAN produces a content-addressed bundle of both files, so the argv is reviewable before apply, but the reviewer must readapply.shto see it.They resolve through
runner_host_spec_for, notrunner_host_deploy_for: these rows depend on no runner population — which is whyrunner_host_wide_refused_operationstakes the spec — so resolving through the deploy would deny srv2, a rostered host with a refused width, the membership its own installed sudoers already authorizes. A host with no roster row contributes a stated refusal comment and no grant.The readback, and why it is not
test -wA supplementary group enters a process's credentials at exec. The converge that applies the grant, and every process already running, still read
present-not-writable— so atest -w /dev/kvmreadback would refuse a host that had just converged correctly, forever. The readback asks the account database instead (id -nG <login>, which names the login explicitly rather than reporting the caller's own stale credential set), and the standing carries it as its own typed fact:KvmGroupEnrolled/KvmGroupNotEnrolled/KvmGroupEnrolmentUnreadable— the third arm is separate because "we could not ask" and "the grant did not land" send an operator to opposite remedies.firecracker_host_readyadmits enrolment (the converge's question — effective at the next incarnation),firecracker_host_ready_in_this_processrequires writability (the boot probe's question, because it opens the device itself). Gating the probe on converge readiness would make it attempt a boot it cannot perform and report a VMM error as an IMAGE verdict.present-not-writablebesideenrolledis not read as a reason to restart a live slot. Nothing is restarted, masked or stopped; a JIT slot picks the group up on its own when its current job ends.Evidence
claim_batchon both witness modules, all PASS:runner_microvm_host_ready_witness(7):readiness_needs_a_reachable_kvm_device_and_the_modeled_version,enrolment_carries_a_host_whose_converging_process_cannot_yet_open_the_device(the discriminating one — it reds if readiness requires this process to open the device),an_unreadable_membership_neither_carries_nor_reads_as_a_missing_grant,the_in_process_predicate_refuses_exactly_where_the_converge_predicate_carries,the_group_readback_matches_a_whole_name_and_not_a_prefix(a substring test would acceptkvm-admin), plus the two pre-existing claims updated for the new field.fleet_converge_plan_witness(2):the_full_host_apply_script_carries_the_hosts_own_executor_grantsasserts the EXACT elevated argv'/usr/bin/sudo' '-n' '/usr/sbin/usermod' '-aG' 'kvm' 'ghrunner'for srv1 and that a non-rostered host contributes nousermodline at all.The fold's output was also read directly:
host_wide_grant_apply_lines(host: srv1)yields the converge state dir, both runner tree roots, the kvm grant and the daemon reload, each fully elevated and quoted.What this does NOT do
It does not attribute a capability to the run that placed it. The class's next-rung trigger — a standing that REFUSES a capability it cannot attribute — is untouched; this makes the modeled path the one that delivers, not the one that can tell whether it did. The roster row records both halves.
Scope limit of the route control, stated because it was demonstrated
both_microvm_steps_pass_the_selected_host_to_the_bindingasserts over the authority — theStepvalues infleet_converge_workflow.dag. It establishes that the authority delivers the expected host to both modes. It does not establish that the emitted workflow does, and those are two different propositions.This is not hypothetical: the claim was green at
1af9f21b9d0while the emitted YAML was wrong. Composing main conflicted in.github/workflows/fleet-converge.yml, I took the base side to settle the conflict and did not re-run the regen, so the authority carried the binding and the artifact GitHub actually runs did not — and a control that never reads the artifact cannot see authority-to-artifact drift by construction.Asserting over step values rather than emitted text is still the right call for what that claim is for. The proposition it cannot carry is carried by the generated-artifact gate, which caught this drift on the real head and failed the step. Without this paragraph a reader sees 18/18 plus a route-repair claim and concludes the emitted workflow is covered — the exact inference that was false one commit ago.
The generalisable form, since it cost a red here: taking the base side of a generated projection is correct for settling a merge and insufficient as the repair. The authority and its projection then disagree, and only the projection is executed. The regen is the second half of the resolution, not optional cleanup.
Not yet run on srv1
Under the spine ruling the actuation is a full-host converge plan+apply on srv1, which is broader than the single mode the brief named. Asking before actuating.
🤖 Generated with Claude Code