Repository navigation
Managed-host cut 2: host-generic unit hold over ManagedHost.unit_hold - #13131
Conversation
gunbc.machine_intake_mtcollins1_maintenance_hold becomes gunbc.managed_host_unit_hold. The take/release procedure and every hold-owning acquire are keyed by an AdmittedUnitHoldSubject minted from a ManagedHost row's unit_hold decision; a host that is not managed, or whose row says ResetNoUnitHold, is a typed refusal. The mtcollins1_unit_hold_key / mtcollins1_unit_hold_store_host roots are deleted and their values enter as the mtcollins1 row's own values. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
briansrls
left a comment
There was a problem hiding this comment.
Reviewed exact head 80a3270eeac79de148ac5feb8e441d747982cba5. The root replacement is largely sound: the old unit-specific module and symbols are deleted without aliases; hold policy comes from ManagedHost.unit_hold; AdmittedUnitHoldSubject, AdmittedMaintenanceHold, and UnitHoldProof are construction-confined; boot, reset-return, and KVM consume admitted subjects/proofs; workflow runner/concurrency placement derives from the row and refuses emission when the host has no hold admission; and the owner-tag recut correctly removes the unit name from the generic holder vocabulary.
One safety-critical gap remains.
The by-hand take/release entries ignore the admitted store_host
maintenance_hold_take(host) and maintenance_hold_release(host) correctly resolve the managed host and produce an AdmittedMaintenanceHold whose subject carries store_host. But the admitted implementations then call file_hold_acquire, observe_file_hold, and release against the process-local constant /var/lib/gunbc/unit-holds; they never establish that the command is actually executing on hold.subject.store_host and they do not route the effect there.
Therefore this command can succeed from another machine:
... managed_host_unit_hold.dag --function maintenance_hold_take --arg host=mtcollins1
It would create a decoy hold in that machine's local /var/lib/gunbc/unit-holds, while the boot on srv1 reads srv1's store and proceeds. The prose instruction “run on srv1” is not the physical-safety interlock. This also contradicts the module's own invariant that every holder operates on the subject's store host and the reason store_host is carried in the admitted subject at all.
Required repair: before either operator entry touches the store, structurally establish that the executing host is subject.store_host, or realize the store effect through an admitted host-operation route targeting subject.store_host. A caller-supplied executor label is not sufficient unless it is joined to a trusted executor observation.
Required controls:
- mtcollins1 admitted with store host srv1, execution observed on srv2 -> refusal before reason lookup or filesystem mutation;
- the same entry observed on srv1 -> reaches the store path;
- release has the same gate.
The durable tag migration itself is acceptable. The free-slot reading closes the currently stranded-holder risk, but because old binaries would write tags the new decoder intentionally rejects, re-check immediately before queueing that the slot is free and that no pre-merge mtcollins1 boot/KVM-observer run is queued or active.
I accept the acceptance-matrix limitation as stated: the holder-tag edit is mechanically consistent (mtcollins1-boot: -> boot-run:), but it is not execution evidence while that witness is 0/28 on main and must remain classified as unverified until the triage lane restores it. That is not a second blocker for this cut.
Exact-head required CI is still in progress. After the store-host gate and its controls land, rerun the directly affected hold/boot/KVM/workflow witnesses and exact-head CI.
…d of a copied, scanned accumulator (review 75039) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…e host The hold store is a local directory, so take/release/acquire run off the store host acted on another machine's store. UnitHoldStoreExecutor (sole_constructor) is minted only when this process's own os.Hostname.ReadShort equals the hostname gunbc.hostname_allocation allocates to the subject's store_host; unit_hold_acquire, the KVM probe's always-release and the operator's take/release all consume it, and the operator entries refuse before the reason lookup. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Hermetic measurement (
No FAIL, no refusal, rc=0 in both arms; every declared |
briansrls
left a comment
There was a problem hiding this comment.
Re-reviewed exact head 8732e2b99e2ab1179ae7aa9222685a898caa5583. The original off-store-host defect is materially closed across the acquire and KVM-release paths: UnitHoldStoreExecutor is construction-confined, its only mint reads this process's own os.Hostname.ReadShort and joins it to gunbc.hostname_allocation, and unit_hold_acquire / the KVM always-release refuse before touching the local store when that join is absent. This also correctly closes the same latent hole in boot, KVM, and reset because those routes converge on unit_hold_acquire. The quadratic store-host dedup is also gone in favor of std.list distinct_by_key.
One construction gap remains in the operator path.
maintenance_hold_*_admitted can cross-wire the maintenance policy of one host to the store subject of another
Both helpers take two independent sealed values:
maintenance_hold_take_admitted(
hold: AdmittedMaintenanceHold,
executor: UnitHoldStoreExecutor,
)
and likewise for release.
The entrypoint passes matching values, but the helper itself has no caller admission and does not prove that hold.subject equals executor.subject. It reads the reason variable and label from hold, but performs the filesystem effect using executor.subject.key.
Because both carriers are obtainable through public admissions, another caller can legitimately obtain:
- an
AdmittedMaintenanceHoldfor managed host A; and - a
UnitHoldStoreExecutorfor managed host B whose store is on the current machine;
then call the admitted helper with both. The result can take/release B's slot under A's maintenance policy and reason while printing A's label. With more than one held host on the same store host, the hostname gate does not distinguish them.
The relation itself needs to be construction-confined. Simplest repair: do not expose a helper taking the two carriers independently. Have the effect take one carrier that contains the admitted maintenance hold plus the executor minted specifically for hold.subject, or keep the helper admitted only to the entrypoint that derives unit_hold_store_executor(subject: hold.subject). A direct mismatch compiler/control RED should show that A's maintenance admission cannot operate B's slot.
The supplied off-host/on-host decision controls and forged UnitHoldStoreExecutor literal RED are useful but do not discriminate this valid-carrier cross-wire.
I accept the stated limit that the on-srv1 operator take/release path is not executed against the real store: for this cut, a non-destructive fold/type proof is preferable to a witness that could acquire or release a real maintenance interlock. Once the carrier relation above is sealed, that is not a blocker.
The old-tag landing precondition still needs the point-in-time store-free check immediately before queueing, because a pre-merge boot/KVM run can recreate an old-tag hold. Exact-head required CI is currently in progress.
… store host Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Hermetic re-measure at the new head (
rc=0, no FAIL or refusal; every declared |
…ct; no helper takes both Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
# Conflicts: # dag/gunbc/host/managed_host.dag # dag/test/claim/machine_intake/mtcollins1_maintenance_hold_witness_test.dag
…retire the residue row the wildcard held Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
briansrls
left a comment
There was a problem hiding this comment.
Re-reviewed exact head 1bf61eb6576e6dad2fb83bd59dd8c26bbc5091a8. Approved.
The remaining hold/executor cross-wire is closed structurally:
maintenance_hold_take_admittedandmaintenance_hold_release_admittedtake onlyAdmittedMaintenanceHold, are caller-admitted to their public operator entries, and deriveUnitHoldStoreExecutorfrom that hold's ownsubject.maintenance_hold_release_on_store_hostderives both the slot key and rendered label fromexecutor.subjectand admits onlymaintenance_hold_release_admitted.kvm_observer_release_on_store_hostlikewise consumes only its executor and admits only the public KVM release route.unit_hold_acquirealready had the corresponding one-subject shape. No remaining function accepts independently obtained maintenance-policy and executor carriers.
The compiler RED is appropriately keyed to the actual enforcement wall: outside attempts to pair hold A with executor B or call either executor-taking release helper are ConstructorCallAdmissionRefused at the four named callees. The sole-constructor controls for the underlying carriers remain beside it.
The new Hermetic route witness closes the previous execution-evidence limitation without touching the live store. It runs the production take/release entries against a modeled hostname, environment and filesystem. On srv2, hostname is the only dispatch and both reason/store effects remain absent; on srv1, take writes a real modeled slot, release frees it, and a subsequent take succeeds. The held-store control proves release starts from an actually held slot.
The main merge is reconciled correctly: cut 4c owns the federation claims, so deleting this branch's duplicate federation witness removes a second authority rather than coverage. The explicit match arms repair the NonFoldResidue drift, and std.list distinct_by_key remains the single linear dedup route.
Exact-head evidence is sufficient: the new route witness is 5/5, modeled filesystem 4/4, the Hermetic boot matrix 28/28, the twelve directly affected hold/boot/KVM/reset/workflow/compiler witnesses are green, generated fleet-converge.yml is byte-identical, and exact-head required witnesses CI succeeded.
Landing precondition remains operational rather than semantic: immediately before queueing, re-read the srv1 slot and ensure no pre-merge boot or KVM observer has created a live mtcollins1-boot: or mtcollins1-kvm-observer: owner, because those intentionally become unrecognized after the durable tag recut. No code blocker remains.
…l lift of the process-holder identity from gunbc.managed_host_unit_hold, re-apply the hold retention argument, union the recovery admit list, take main's roster retirement cause Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Cut 2 of the managed-host untangle (
docs/plans/managed-host-untangle.md). Work itemadhoc-fb595477-42d, parent warm-crane-577.What changed
gunbc.machine_intake_mtcollins1_maintenance_holdis replaced bygunbc.managed_host_unit_hold(dag/gunbc/host/managed_host_unit_hold.dag). The name follows the vocabulary the corpus already uses: "unit hold" for the slot and its proof (UnitHoldProof,unit_hold_acquire,unit_hold_store_root); "maintenance" is one kind of holder.AdmittedUnitHoldSubjectissole_constructor, minted only byadmit_unit_hold_subjectfrom aManagedHostrow'sunit_hold. A label with no row isUnitHoldHostNotManaged; a row withResetNoUnitHoldisUnitHoldHostNotRequired. No arm derives a key from a label.unit_hold_acquiretakes the subject (store root fixed inside).UnitHoldProofcarries the subject it was acquired for;unit_hold_proof_refusalcompares the proof's host with the host about to be written.AdmittedMaintenanceHold(sole_constructor) = hold subject + the reason variable declared bygunbc.host_maintenance_hold_reason(new, same shape asgunbc.host_reset_boot_selection).GUNBC_MTCOLLINS1_MAINTENANCE_REASONis unchanged and lives there as mtcollins1's row.managed_hosts()now authorsResetUnitHoldRequired { key: operator_host_mtcollins1, store_host: operator_host_srv1 }directly;gunbc.managed_hostno longer imports the hold module.mtcollins1_unit_hold_key,mtcollins1_unit_hold_store_host,mtcollins1_maintenance_reason_env,mtcollins1_boot_acquire_unit_hold,mtcollins1_kvm_observer_acquire_unit_hold,mtcollins1_kvm_observer_release_unit_hold,mtcollins1_maintenance_hold_take,mtcollins1_maintenance_hold_release, and the unusedunit_hold_proof_key.Consumers cut over:
gunbc.host_reset_return_run(reads the hold throughadmit_unit_hold_subject),gunbc.runner_host_grants(store root provisioned onunit_hold_store_hosts()),gunbc.fleet_converge_workflow,gunbc.auth.privileged_effect_census,gunbc.durable_exclusive_hold_file_store(admit list), and the unit procedure modulesmtcollins1_actuate,mtcollins1_media_attach,mtcollins1_boot_run,mtcollins1_kvm_observer_observe(one import line plus the call sites; prose-only edits inmtcollins1_boot_admission,_boot_authorization,_boot_dry_realization).Current head
1bf61eb6576— what changed since8732e2b99e2and what was runSealed hold/executor pairing (side chat at
8732e2b99e2).maintenance_hold_take_admittedandmaintenance_hold_release_admittedno longer take an executor: each mints it from its ownhold.subject, so no function accepts a hold for A beside an executor for B. The two functions that do take aUnitHoldStoreExecutor(maintenance_hold_release_on_store_host,kvm_observer_release_on_store_host) read slot and label from the executor's own subject and areadmit_callers-sealed to their one in-module caller. Checked as asked:unit_hold_acquirealready derived the executor from its own subject and passed only that on; the KVM release passed only the executor but its inner function was unsealed, now sealed. Mismatch RED:managed_host_unit_hold_forged_probe_witnessa_hold_cannot_be_operated_with_another_subjects_executorrequiresConstructorCallAdmissionRefusedatmaintenance_hold_take_admitted,maintenance_hold_release_admitted(each called with hold A and executor B),maintenance_hold_release_on_store_hostandkvm_observer_release_on_store_host. The pinned refusal is the caller admission; the census reports no separate blocking row for the surplusexecutor:argument, so none is claimed.Executed store-host controls (
dag/test/claim/host/managed_host_unit_hold_store_host_witness_test.dag, new). The productionmaintenance_hold_take/maintenance_hold_releaseentries formtcollins1run against a modeled machine (hostname, environment, modeled store) and the claims assert the route: observed onsrv2, take and release each refuse with the hostname read as the ONLY dispatch (noshell.Env, noFilesystem) and the store unchanged; observed onsrv1, each reaches the store (hostname first, reason read, store written; a take after the release succeeds); plus a control that a second take over the held store is refused as already held. No mutation arm (gate removed) was run against this file.Merge with main / cut 4c (#13139). Conflict in the fixture's admit list (both sets kept). Cut 4c moved the boot-federation claims to its own witness and deleted their module, so the
mtcollins1_boot_federation_witness_test.dagthis PR had split out is deleted; decision 6 below is superseded.CI floor refusal at
c88b4813456, fixed.NonFoldResidueRosterDiverged: moving the store effect intounit_hold_acquire_on_store_hostcarried a wildcard arm with it. The wildcard is replaced by the explicit outcome arms and the::unit_hold_acquireresidue row is deleted (one row remains,::start_time_text).Evidence at exactly
1bf61eb6576:claim_batch --claim-run --hermeticon a BuildBuddy runner with a bound memory cgroup, checkout asserted at the pin (route: gunbc#12550 comment 5889444969): store-host route witness 5/5,modeled_filesystem_witness_test4/4,mtcollins1_boot_acceptance_matrix_test28/28. This replaces the "unmeasured" standing of the last two in section 1 below, and the matrix now passes with the extra hostname read. The same three were also 5/4/28 at0056a10b392,7de5e50d58aandc88b4813456.gunbc run --claim-run, binary/cargo-target/snappy-heron-23/release/gunbcversion1bf61eb6576, all green:managed_host_unit_hold_witness17/17,managed_host_unit_hold_forged_probe_witness4/4,mtcollins1_unit_hold_forged_probe_witness_test5/5,managed_host_witness3/3,managed_host_forged_probe_witness3/3,host_reset_return_witness53/53,mtcollins1_boot_run_witness_test35/35,mtcollins1_kvm_observer_observe_witness_test11/11,unit_hold_store_provision_witness2/2,authorization_pattern_selection_witness23/23,fleet_converge_plan_witness87/87,non_fold_residue_frontier_test5/5.fleet-converge.ymlequal to the committed file at1bf61eb6576.ec9e79d4661), cut 4c's federation witness, andsol_hold_stdin_wet(not run, see below). Exact-head CI is the required run on this head.Changes after the first review round (written at
8732e2b99e2; item 1's "Not executed" note is superseded by the section above)1. Store effects require a process observed on the store host (side-chat REQUEST_CHANGES at
80a3270eeac).unit_hold_store_rootis a local directory, somaintenance_hold_take/releaserun on srv2 for mtcollins1 would have acted on srv2's store while srv1's stayed free.sole_constructorcarrierUnitHoldStoreExecutor, minted only byunit_hold_store_executor(subject), which itself readsos.Hostname.ReadShortand requires it to equal the hostnamegunbc.hostname_allocationallocates tosubject.store_host. These are the same two authoritiesgunbc.host_reset_return_runobserver_self_corroborationalready reads to establish which machine a run is on; no second authority and no caller-supplied executor parameter. Unreadable hostname or unallocated store host refuse.unit_hold_acquire(gate inside the one mint, with the store effect moved tounit_hold_acquire_on_store_host, sealed to it); the KVM probe's always-release.mtcollins1_boot_host_admission, an environment value); the reset run compared the observer label with the store host and acquired the hold before its own hostname corroboration ran, so a mislabelled runner took a hold in the wrong store (it still refused before any controller write); the KVM always-release read and released the local store unchecked. All now pass through the gate.managed_host_unit_hold_witness:w_a_process_observed_off_the_store_host_is_refused_and_one_on_it_is_admitted(real mtcollins1 subject; supplied readingsrv2refuses naming it,srv1admits, unreadable/empty refuse);w_a_store_host_with_no_allocated_hostname_refuses_the_executor;w_the_executor_carrier_is_minted_only_from_this_process_own_hostname(the real read; read-only). The forged-carrier witness now also requiresSoleConstructorViolationatUnitHoldStoreExecutorandConstructorCallAdmissionRefusedatunit_hold_acquire_on_store_host.mtcollins1_boot_acceptance_matrix_test, whose dry realization already answershostname -sassrv1; that file runs only in Hermetic mode and its route assertions now see one more read, so it needs the Hermetic measurement below at this head.2.
unit_hold_store_hosts_of(review 75039): the copied, scanned accumulator is replaced by prepend-and-reverse plusstd.listdistinct_by_key; a claim covers three rows naming one store host.Evidence for this round. At
b2a75609d8e(binary/cargo-target/snappy-heron-23/release/gunbc, versionb2a75609d8e),gunbc run --claim-run, all green:managed_host_unit_hold_witness17/17,managed_host_unit_hold_forged_probe_witness3/3,mtcollins1_unit_hold_forged_probe_witness_test5/5,managed_host_witness3/3,managed_host_forged_probe_witness3/3,host_reset_return_witness53/53,mtcollins1_boot_run_witness_test35/35,mtcollins1_kvm_observer_observe_witness_test11/11,unit_hold_store_provision_witness2/2,authorization_pattern_selection_witness23/23,fleet_converge_plan_witness87/87,non_fold_residue_frontier_test5/5. Generatedfleet-converge.ymlequal to committed atb2a75609d8e. The head8732e2b99e2is that commit merged with main; main changedgunbc.fleet_converge_workflowand the generated workflow in that merge, and I have not re-run anything at8732e2b99e2— its workflow drift and witnesses are for exact-head CI. Sections below this one describe the first round at80a3270eeacand are otherwise unchanged.Landing precondition
Before this merges, the srv1 hold store (
/var/lib/gunbc/unit-holds) must hold no live slot whose owner starts withmtcollins1-boot:ormtcollins1-kvm-observer:. This PR changes those two owner tags (decision 1 below; kept per warm-crane-577). A hold written under an old tag decodes as unrecognised after this lands: it still excludes every new acquirer, but it can no longer be recovered as a dead holder or released from the operator entry, so it would have to be cleared by hand. Reading, relayed by warm-crane-577 (2026-10-03): eager-gull-22 read srv1/var/lib/gunbc/unit-holds; the latest event ismtcollins1.36 = free|mtcollins1-boot:37102391062, i.e. the slot is free (last released by a boot run), so no hold is live under an old tag. eager-gull-22 will take no hold and start no mtcollins1 boot until this PR lands. That reading is theirs, not mine: this PR does not check the store and I have not touched the host. It is a point-in-time reading, so a boot or probe dispatched from another branch before the merge would reopen the question.operator-maintenance:andhost-reset-return:holds are unaffected.Operator commands after this lands
Run on the store host (srv1), in the operator's own session, from the repository root. The host is an argument and has no default.
Take a maintenance hold on Mt. Collins unit 1:
Release it:
These replace
--entry dag/gunbc/machine_intake/mtcollins1_maintenance_hold.dag --function mtcollins1_maintenance_hold_take/mtcollins1_maintenance_hold_release, which no longer exist. The refusal arms of both entries were executed byw_the_operator_entries_refuse_an_unnamed_or_unmanaged_host; the commands above were not run against a real store in this session (no hardware or host was touched), so the admitted take/release path is exercised only up to the store call by the witnesses.Decisions a reviewer should check
mtcollins1-boot:→boot-run:,mtcollins1-kvm-observer:→kvm-observer:(and the always-release ref). A generic module stamping another unit's name on a hold is the thing this cut removes. Consequence: a hold stranded under an old tag by a run that died decodes as unrecognised and refuses until cleared by hand.operator-maintenance:andhost-reset-return:are unchanged, so an operator hold in place survives. If this should wait for cut 7, say so and I will restore the two tags.gunbc run … --entry dag/gunbc/host/managed_host_unit_hold.dag --function maintenance_hold_take --arg host=mtcollins1(same formaintenance_hold_release). An empty or unknown host refuses before the store is touched.unit_hold_admission_for; if the row is not admitted,fleet_converge_yml_after_reset_assignmentrefuses to emit. Generated.github/workflows/fleet-converge.ymlis byte-identical (check below). No mode, job, input, step id or env var changed.admit_callerslists in the generic module still name the mtcollins1 boot and KVM callers. Those are the seals' current callers and move with cuts 4d/5.mtcollins1_boot_federation_witness_test.dag(cut 4c's subject), and the hold claims moved todag/test/claim/host/managed_host_unit_hold_witness_test.dag.Terminal receipt
Binary for every run:
/cargo-target/snappy-heron-23/release/gunbc, built locally from this branch;gunbc --versionprinted the sha named with each result. Command:gunbc run --claim-run --source-root dag --source-root src/v2 --entry <file>.1. Consumer roster and witnesses
Roster by the plan's census method (reverse
importedges overdag/andsrc/v2/), recomputed at80a3270eeac.Pproduction,Wwitness.Full roster of every deleted or changed root
Three witnesses reach the change without an import edge and were added by name:
mtcollins1_unit_hold_forged_probe_witness_test(reads the probe file),managed_host_unit_hold_forged_probe_witness_testandmanaged_host_forged_probe_witness_test(inline probe source), plusfile_hold_plan_refusal_probe_witness_test.Full run, 41 files, at
ec9e79d4661(binary shaec9e79d4661):approval_device_enrolment_code_witness_testauthorization_pattern_selection_witness_testdurable_exclusive_hold_file_store_wet_witness_testdurable_exclusive_hold_witness_testexecutor_privileged_operation_witness_testfile_hold_plan_refusal_probe_witness_testfleet_fleet_converge_checkout_pin_witness_testfleet_fleet_converge_plan_witness_testfleet_organization_runner_roster_read_witness_testgcp_iam_converge_witness_testhost_managed_host_forged_probe_witness_testhost_managed_host_unit_hold_forged_probe_witness_testhost_managed_host_unit_hold_witness_testhost_managed_host_witness_testlive_deploy_approval_broker_helper_grant_testmachine_intake_host_capture_sol_crlf_witness_testmachine_intake_host_capture_sol_nul_fill_witness_testmachine_intake_megarac_media_convergence_witness_testmachine_intake_mtcollins1_boot_acceptance_matrix_testmachine_intake_mtcollins1_boot_authorization_witness_testmachine_intake_mtcollins1_boot_diagnostic_bundle_witness_testmachine_intake_mtcollins1_boot_federation_witness_testmachine_intake_mtcollins1_boot_run_witness_testmachine_intake_mtcollins1_census_medium_readback_witness_testmachine_intake_mtcollins1_census_member_readback_witness_testmachine_intake_mtcollins1_kvm_observer_observe_witness_testmachine_intake_mtcollins1_kvm_observer_protocol_wet_witness_testmachine_intake_mtcollins1_stale_power_off_witness_testmachine_intake_mtcollins1_unit_hold_forged_probe_witness_testmachine_intake_sol_hold_stdin_wet_witness_testmodeled_filesystem_witness_testnamecheap_workflow_witness_testnon_fold_residue_frontier_testrunner_runner_microvm_host_ready_witness_testrunner_runner_microvm_slot_reserve_witness_testrunner_runner_service_activation_witness_testrunner_unit_hold_store_provision_witness_testtoolchain_home_standing_witness_testwitness_floor_workflow_consolidation_witness_testworkflow_capability_closure_witness_testworkflow_dispatch_input_witness_testsol_hold_stdin_wet_witness_testis not run and not claimed. Two attempts each printed 30 claims and then the session container restarted with no exit status. Per the triage lane (mtcollins1 boot witnesses: re-derive four reds against the current contract; guard sol_hold's pid-1 stand-ins #13153) those restarts were the witness itself SIGKILLing pid 1 of the session container, so it must not be run in a session; it stays unmeasured for this PR until mtcollins1 boot witnesses: re-derive four reds against the current contract; guard sol_hold's pid-1 stand-ins #13153 lands.a5a9957b66b(tree checked out separately, same binary): sameFAILnames and samePASSnames, file by file. What that comparison does and does not show (corrected 2026-10-03 after mtcollins1 boot witnesses: re-derive four reds against the current contract; guard sol_hold's pid-1 stand-ins #13153's triage):gunbc run --claim-runexecutes in Wet mode and prints onlyFAIL <name>, with no cause. A claim whose realization is Hermetic-only therefore REFUSES under it and is printed asFAIL, on any tree. For such a claim "red at head, red at base" compares two mode refusals and says nothing about this change.mtcollins1_boot_acceptance_matrix_test(28/28FAILon both trees) is exactly that case: its dry realization is Hermetic-only, and the triage lane reports all 28 pass on main underclaim_batch(Hermetic). My earlier wording ("identical at merge-base, not introduced by this cut") was not supported for this file and is withdrawn. It is unmeasured for this PR by my runs. This PR edits one of its claims (a_second_run_for_a_held_unit_writes_nothing_to_the_controller: slot key and expected holder tagboot-run:4141@), so it needs a Hermetic measurement at this head; that needs a memory cgroup and is not run bare in a session. Hermetic result, from CI: required run 37151981302,floorjob, head80a3270eeac(apull_requestrun, so the evaluated tree is that head merged with main). The floor log carries[changed-witness] identity=test.claim.machine_intake.mtcollins1_boot_acceptance_matrix_test.a_second_run_for_a_held_unit_writes_nothing_to_the_controller standing=planned-and-passed disposition=planned_as_changed_witness outcome=passed. So the one claim this PR edits is measured green in Hermetic mode. For the rest of the file the evidence is weaker and I state it as such: the floor's plan names 37 identities of this module through body reach, and the run reportsplanned=695 executed=695 claims_failed=0 … verdict=FloorCleanwithknown_red_held=5; the log has no per-claim outcome line for the other matrix claims and does not name the five held identities, and the run publishes no terminal-ledger artifact, so I am not asserting "28/28 passed at this head" from it.The same floor run reports all 24 changed witnesses of this PR
planned-and-passed:managed_host_unit_hold_witness14,managed_host_unit_hold_forged_probe_witness3,mtcollins1_boot_federation_witness_test3,unit_hold_store_provision_witness2,authorization_pattern_selection_witness1, and the matrix claim above.modeled_filesystem_witness_test(4/4FAILon both trees) has the same signature (every claim fails, including ones unrelated to the hold) and uses the same modeled-world harness. I cannot tell a mode refusal from a claim failure in its log, so I treat it as unmeasured too. This PR changes one import line in it. The CI floor run above mentions it only as a body-reach seed (two_contenders_for_one_unit_get_one_hold) with no outcome line, so it is still unmeasured in Hermetic mode at this head; that needsclaim_batchon a fleet host.evaluate_in_witness_frame(the modeled-world harness); the other eight do not.mtcollins1_kvm_observer_protocol_wetlogsmktemp: failed to create directory via template 'target/gunbc_kvmrel.XXXXXX'.) What the comparison does support for these eight: their passing claims pass on both trees, and no claim that passes at base fails at head.approval_device_enrolment_code1,approval_broker_helper_grant1,host_capture_sol_crlf1,host_capture_sol_nul_fill3,mtcollins1_boot_acceptance_matrix28/28,mtcollins1_boot_diagnostic_bundle1,mtcollins1_kvm_observer_protocol_wet7,modeled_filesystem4/4,witness_floor_workflow_consolidation1,workflow_dispatch_input1.Re-run after merging main, at
80a3270eeac(binary sha80a3270eeac), the eight files closest to the change, all green:managed_host_unit_hold_witness14/14,managed_host_unit_hold_forged_probe_witness3/3,managed_host_witness3/3,unit_hold_store_provision_witness2/2,authorization_pattern_selection_witness23/23,non_fold_residue_frontier_test5/5,fleet_converge_plan_witness87/87,mtcollins1_boot_run_witness_test35/35. The other files were not re-run after the merge.Generated workflow. A scratch driver (not committed) compared
artifact_generate(FleetConvergeYamlArtifact)with the committed file: equal at3dddd7bd6a9and again at80a3270eeac. The same driver goes red under RED A below, so it can fail.2. Same-path REDs
unit_hold: ResetNoUnitHoldinmanaged_hosts(), tree3dddd7bd6a9):managed_host_unit_hold_witnessfailsw_the_managed_row_is_admitted_to_its_hold_with_its_own_key_and_store(and the two fixture claims that derive from the real row);unit_hold_store_provision_witnessfails both claims; workflow generation returnsREFUSED gunbc.fleet_converge_workflow: the mtcollins1 boot job runs on its unit hold's store host, and managed host 'mtcollins1' declares no unit hold (ResetNoUnitHold) … No workflow yaml was emitted.Restored: all green.maintenance_hold_reason_envreturnsnone, treeec9e79d4661): exactly one claim fails,w_the_managed_row_is_admitted_to_its_hold_with_its_own_key_and_store; the other 13 pass. Restored: 14/14.w_a_host_that_is_not_a_managed_host_is_refused_by_nameruns the same fold against labelmtjade1and against the real label with an empty roster;w_the_operator_entries_refuse_an_unnamed_or_unmanaged_hostruns the entries themselves.w_a_managed_host_with_no_unit_hold_is_refused_and_has_no_store,w_a_held_host_with_no_reason_variable_is_refused_for_maintenance(both admitted tomanaged_host_fixture).managed_host_unit_hold_forged_probe_witnessrequiresSoleConstructorViolationatAdmittedUnitHoldSubject,AdmittedMaintenanceHold,UnitHoldProof, andConstructorCallAdmissionRefusedatunit_hold_acquire,boot_run_acquire_unit_hold,kvm_observer_acquire_unit_hold,kvm_observer_release_unit_hold, with a class-scoped clean control.3. Corpus sweep at
80a3270eeacgit grepoverdag src docs .github artifactsfor the old module name and each deleted symbol listed above: the only hits are indocs/plans/managed-host-untangle.md(the dated plan; residue, not edited by cuts). Separately,dag/test/claim/durable_exclusive_hold_witness_test.daguses the string"mtcollins1-boot:4242"as an opaque owner in the std fold's witness; it never reaches this module's decoder (residue).Entry-path strings:
gunbc.non_fold_residue— the two rows for the moved file now readdag/gunbc/host/managed_host_unit_hold.dag::start_time_text/::unit_hold_acquire, re-sorted into place (non_fold_residue_frontier_test5/5).gunbc.ci_specandv2.workflow.floor_unimported_bare_provider_debt_rostercarry no row for the moved file or the renamed witness (grepped).4. No aliases
Nothing re-exports or wraps a deleted root; no
mtcollins1_*function calls into the generic one as a one-liner. The old module file is gone (renamed, with the unit-fixed declarations deleted).🤖 Generated with Claude Code