Skip to content

RLM-2a: typed fleet plan/apply + dashboard deploy receipts, RoadmapLaunchDeploymentReceipt (total verdict), root-tree OID readback, BeltTickReceipt v4, systemd unit standing, live observers, run/artifact bindings, content-addressed persistence, generated receipt mode - #9761

Merged
gunbai-bot[bot] merged 26 commits into
mainfrom
session/crisp-newt-85
Aug 31, 2026

Conversation

@gunbai-bot

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

Copy link
Copy Markdown
Contributor

RLM-2a — the MODELING half of RLM-2 (docs/plans/roadmap-launch-mvp-plan.md §3 RLM-2). Binds the RLM-1 join: main 0beef8a2c1a035f4f1f0507e77075bdeaba74cba, tree 79d55f2e63af52c96a51a08dac969ff10fa30194, launch_admission_contract_digest_hex = 8b884d701d7a356e (frozen as gunbc.roadmap_launch_deployment_cli rlm1_contract_digest_frozen; the receipt producer refuses at R if the live digest drifts from it). No production actuation: RLM-2b is the manager/operator's wet transaction and changes no source.

The 10 deliverables → module.symbol

  1. Typed plan/apply and dashboard transaction receipts — gunbc.fleet_converge_receipt FleetConvergePlanReceipt / FleetConvergeApplyReceipt (+ JSON wire, identity hex, admit_apply_plan_binding with four distinct refusals), minted inside gunbc.fleet_converge_plan_cli fleet_converge_plan_wet / fleet_converge_apply_wet before the ProcessExit projection (plan receipt lives in the plan artifact dir so the existing upload/download carries it; apply receipt has its own artifact). gunbc.live_deploy.apply_receipt LiveDeployApplyReceipt (expected revision, candidate revision + surface + root-tree OID, target decision, apply outcome, one independent post-apply readiness read, fleet provenance, completed_at), minted by the new gunbc.live_deploy.apply live_deploy_apply_srv1_transaction_wet around the unchanged fold; the plain operator entry is untouched.
  2. Subject / total facts / verdict — gunbc.roadmap_launch_deployment_receipt RoadmapLaunchDeploymentSubject, RoadmapLaunchDeploymentFacts (18 members, each a typed standing with its own refusal arms), roadmap_launch_deployment_blockers (every member consulted, blockers accumulated), RoadmapLaunchDeploymentVerdict = DeploymentComplete { subject, facts, proof } | DeploymentIncomplete { subject, facts, first_blocker, further_blockers }. DeploymentCompleteProof is sole_constructor: no module other than the join can write it, and the join writes it in exactly one place (roadmap_launch_deployment_verdict, empty blocker list). Both arms serialize (roadmap_launch_deployment_receipt_document).
  3. Deployed root-tree OID readback — gunbc.live_deploy.deployed_tree_observation deployed_tree_root_tree_argv (git rev-parse HEAD: — the colon form is the one spelling the portability wall admits; ^{tree} is refused by portable_remote_word_char_allowed), one more leg on the same DeployedTreeLocus/run_typed_argv_transport; DeployedTreeObserved gains tree: GitObjectId; deployed_root_tree_standing requires OID equality AND DeployedScopeMatchesCommit. Candidate side: gunbc.live_deploy.apply_receipt observe_candidate_root_tree_oid (same colon form on the deploying checkout).
  4. BeltTickReceipt v4 — gunbc.roadmap_belt_actuate schema roadmap-belt-tick-receipt/v4, BeltTickExecutionStanding = TickExecuted { instance_id, deployed_revision, spawn_mode } | TickExecutionWithheld { refusal }, receipt_identity derived (belt_tick_receipt_identity_hex), written on the wire and verified on decode; minted at belt_run_once_cli_in via belt_tick_execution_standing_for_instance (the instance's fleet_revision_standing + roadmap_belt_production_spawn_mode). A v3 document refuses the decoder (witness_v3_tick_receipt_refuses_the_v4_decoder). Freshness: gunbc.roadmap_launch_deployment_observe belt_tick_freshness (after completed_at of the dashboard receipt, within 3 × the emitted 60s cadence).
  5. Exact systemd standing — gunbc.live_deploy.unit_standing: extdeps.systemd.systemd SystemdUnitProperty widened (LoadState, UnitFileState, SubState, Result, ExecMainStatus, ExecStart, User, WorkingDirectory, Unit, NextElapseUSecMonotonic, TimersMonotonic) and read through the existing systemd.Systemctl.ShowProperty; expectations DERIVED from R's emitted units (gunbc.live_deploy.emit live_deploy_serve_unit_file / live_deploy_belt_service_unit_file / live_deploy_belt_timer_unit_file, factored out of the doc producers); three judgements modeled on what the units are: dashboard simple (loaded/enabled/active + exact ExecStart/User/WorkingDirectory), belt timer (loaded/enabled/active-waiting, exact Unit= target, OnBootUSec + OnUnitInactiveUSec entries present), belt oneshot (static, last Result=success, ExecMainStatus=0, exact ExecStart/User/WorkingDirectory, inactive between ticks accepted). Timer cadence VALUES (OnBootUSec, OnUnitInactiveUSec, AccuracyUSec) are normalized through extdeps.systemd systemd_duration_usec (systemd.time(7), std.measure Microsecond) and compared against expectations derived from R's emitted timer unit — the former structural-only residue is dissolved; 60s and 1min are one value.
  6. Live /healthz, /instance.json, /workflow.json observers + decoders — gunbc.roadmap_launch_deployment_observe (observe_healthz → observe_running_release_identity; dashboard_instance_document_decode; roadmap_workflow_document_decode with the embedded belt_tick decoded by the receipt's own decoder — 200 is not sufficient, absent/unreadable tick refuses). Renderers are no longer cited as evidence anywhere on the receipt path.
  7. srv1 / effective-principal binding — plan refuses unless observed hostname == workflow host input (FLEET_CONVERGE_EXPECTED_HOST), records the observed host; the join requires plan/apply observed host == srv1 and the receipt run's own hostname == srv1; effective principal via extdeps.access.posix_effective_principal (whoami) must equal the emitted belt ServiceUser; footprint / provider (dispatch_actuator_selection → belt_provider_preflight_for_instance) / dispatch_preflight_for_instance all run in that same process and bind to the active instance.
  8. Revision/run/artifact bindings + shared concurrency — gunbc.actions_run_binding (GITHUB_REPOSITORY, GITHUB_WORKFLOW_REF, GITHUB_RUN_ID, GITHUB_SHA — the last two variable names added to extdeps.github.actions_environment), RLM_EXPECTED_REVISION as the independent operator input, admit_run_revision, run_binding_names_workflow_file; every receipt carries its binding and the join checks repository / workflow file / run id / revision per run. One per-host mutation domain: gunbc.fleet_workflow_steps fleet_host_mutation_concurrency_group_expression (gunbc-host-mutation-${{ inputs.host }}) now on the fleet-converge job, the dashboard-deploy job and the receipt job (replaces the dashboard-only literal group). Observation window opened and closed (WindowSnapshot: main, desired, deployed revision + tree, running release, transition, active instance) → WindowChanged blocker.
  9. Durable content-addressed persistence + artifact — gunbc.roadmap_launch_deployment_cli persist_receipt: canonical bytes staged at target/rlm-launch-deployment-receipt/receipt.json, SHA-256 by sha256sum, written with Filesystem.WriteOwnerOnly (O_EXCL) to <instance_receipts_dir>/launch-deployment/<sha256>.json, digest read back and compared (a differing pre-existing file at the address refuses); the staged copy is uploaded as run artifact rlm-launch-deployment-receipt with always() and 90-day retention. Incomplete receipts persist too; exit 0 only for a persisted Complete.
  10. Generated mode — gunbc.fleet_converge_workflow: mode rlm_launch_deployment_receipt, inputs expected_revision, apply_workflow_run_id, dashboard_workflow_run_id, new job fleet_converge_rlm_launch_deployment_receipt_job (host-pinned runner, WIF + fleet key agent for the FleetSsh tree readback, downloads the three predecessor receipts by run id, uploads its own), apply-receipt upload on the apply mode, dashboard mode switched to the receipted entry with env; .github/workflows/fleet-converge.yml regenerated via generated_artifact_gate.dag --function main_wet, never hand-edited. CI targets enrolled in gunbc.ci.ci_spec gunbc_run_step_targets.

Red controls (all hermetic; RED committed first, each replaces one member of an otherwise Complete population)

dag/test/claim/roadmap/roadmap_launch_deployment_receipt_witness_test.dag — positive control witness_complete_population_is_complete, then one witness per ruling row: plan/apply/dashboard run at another SHA; plan run-id substitution; apply bound to another plan; dashboard bound to another R; input srv1 vs observed host srv2 (plan) and receipt-run host srv2; candidate/deployed root-tree mismatch; v3 / stale / wrong-instance / wrong-revision / AutomaticReady tick; disabled timer beside a fresh tick; inactive-successful oneshot positive control (the Complete fixture itself) + active-mid-tick positive control; wrong principal; observation window changed; and the four destructive falsifiers run synthetically — transition marker (ActuationInhibited), unwritable root (FootprintRefused), missing provider credential (ProviderPreflightRefused), unobservable attempt ledger / absent tick on /workflow.json; desired ref behind R. Totality: two substitutions retain both blockers; Incomplete document carries its blockers; receipt identity stable and discriminating.

Supporting witnesses: fleet/fleet_converge_receipt_witness_test.dag (round trips, tamper → identity refusal, four plan-binding refusals, run-binding predicates), live_deploy/apply_receipt_witness_test.dag, live_deploy/unit_standing_witness_test.dag (ExecStart parse, disabled timer RED, inactive-successful oneshot GREEN, wrong user RED, expectations derived from the srv1 spec), roadmap/roadmap_launch_deployment_observe_witness_test.dag (ISO-8601 epoch oracle values, four freshness arms, /instance.json and /workflow.json decoders incl. embedded v3 → Unreadable, v4 tamper refusal, root-tree argv admitted by the portability wall, root-tree standing mismatch).

Rework for review 5061891290 (REQUEST_CHANGES on 06c2e31) — all seven findings

  • P0-1 (apply can mutate at Q≠R) — gunbc.fleet_converge_plan_cli: both fleet_converge_plan_wet and fleet_converge_apply_wet read RLM_EXPECTED_REVISION (gunbc.actions_run_binding read_expected_revision) and refuse via admit_run_revision — a typed comparison of two origins — BEFORE any actuation (fleet_converge_locked_apply_script is unreachable when Q≠R). The admitted revision is carried on the apply receipt (expected_revision_admitted, in identity + wire). Workflow env regenerated: RLM_EXPECTED_REVISION: ${{ github.event.inputs.expected_revision }} on the plan and apply steps. RED: witness_apply_admitted_against_q_is_incomplete_at_apply_receipt.
  • P0-2 (exit-0 PartiallyApplied reaches Complete) — gunbc.fleet_converge_plan FleetConvergeApplyTerminal (FullyApplied | PartiallyApplied { refused_axis_count, detail }) with wire spelling + decoder; carried on the plan artifact and BOTH fleet receipts; the join's apply_outcome_blockers requires FullyApplied and expected_revision_admitted == subject.revision. RED: witness_partially_applied_exit_zero_is_incomplete_at_apply_receipt (fixture is PartiallyApplied under a green exit; first_blocker=apply_receipt).
  • P1-3 (timer cadence VALUES) — extdeps.systemd systemd_duration_usec models systemd.time(7) span normalization (usec→hours spellings, microsecond result, malformed part ⇒ Absent — never a partial sum). TimerUnitExpectation gains on_boot_usec/on_unit_inactive_usec/accuracy_usec DERIVED from R's emitted timer unit (timer_directive_duration_usec over the same directives; one authority — gunbc.roadmap_launch_deployment_observe belt_tick_cadence_seconds_derived now derives the freshness bound from the same emitted belt_tick_cadence, deleting the hand-typed 60). judge_belt_timer compares normalized OnBootUSec/OnUnitInactiveUSec (TimersMonotonic) and AccuracyUSec against those values; each mismatch is a typed BeltTimerRefused naming the property in decimal usec. REDs: witness_timer_with_wrong_cadence_value_refuses (wrong cadence beside an otherwise-clean timer), witness_systemd_duration_normalizes_equal_spellings, witness_derived_timer_expectation_carries_the_emitted_cadence.
  • **P1-4 (run provenance: three predecessors API-read + current-run binding; the split is stated under the RLM-2b sequence) — subject repository is now gunbc.repository gunbc_repository.full_name (canonical authority, not restated from the observed run). RunProvenanceFact on the facts: each predecessor (plan/apply/dashboard) read back through the runs API (extdeps.github.workflow_runs GetRun, which now carries path) and required to be conclusion=success, head_sha == R, path == subject.workflow_path, run_id exactly the bound input; the receipt run's own GITHUB_WORKFLOW_REF must name the generated workflow file (run_binding_names_workflow_file). Dashboard provenance carries the exact predecessor receipt IDENTITIES (plan_receipt_identity/apply_receipt_identity on LiveDeployFleetProvenance, populated in live_deploy_apply_srv1_transaction_wet from the two downloaded receipts — the workflow's dashboard job now downloads both) and the join recomputes both identities from the receipts it read. REDs: the six *_is_incomplete_at_run_provenance witnesses + witness_dashboard_citing_another_plan_receipt_is_incomplete_at_dashboard_receipt + witness_dashboard_receipt_with_tampered_plan_receipt_identity_refuses.
  • P1-5 (whole LeaseEpoch on the plan receipt) — FleetConvergePlanReceipt gains lease_resource_fingerprint, lease_owner_fingerprint, lease_generation beside lease_key (identity + wire + decoder). REDs: three per-member tamper witnesses.
  • P1-6 (routed observation) — rlm_routed_base_url() derives the production endpoint from the deployment authority (deployment_tailnet_url(spec: deployment_spec_srv1())); /healthz, /instance.json, /workflow.json are observed THROUGH that routed base (extdeps.http GetBounded, observe_*_routed); readiness and the workflow/instance facts come from the routed reads; the localhost read remains only as the complementary release-binding probe. An underivable route is a typed HealthzRefused, never a localhost fallback.
  • P1-7 (structured facts serialization) — roadmap_launch_deployment_receipt facts_json serializes ALL facts members as a typed-arm JSON object (each member {arm, …payload}, embedded receipts as their full receipt JSON); the receipt identity is derived from subject_identity_text + serialize_json(facts_json(f)), and the document carries facts (structured) beside facts_text (presentation lines, no longer identity-bearing). RED: witness_receipt_document_facts_are_machine_readable recovers frozen-join members from the JSON document without parsing prose.

Wet-template corrections (review findings a+b): R is the exact admitted MAIN revision selected AFTER this PR merges (possibly a later descendant chosen by the operator) — not definitionally this PR's merge commit; and predecessor run ids are captured from the receipt-bound artifacts of the runs the operator actually dispatched (each receipt names its own run_id), never discovered via an uncorrelated gh run list --limit 1.

Verification status — FINAL, on head f474d96575066e4227c9a49089c8ca8138e8f827

CI (the evidence of record): run 33368298684, headSha f474d96575066e4227c9a49089c8ca8138e8f827 — all 5 checks SUCCESS; required-floor: verdict=FloorClean unexpected_failures=0 verdict_incomplete=0 non_verdict_unenrolled=0 stale_non_verdict=0; changed-witness sublane 107/107 identities standing=planned-and-passed, zero in any other standing — including both BuildBuddy-OOM files, all 19 review-5061891290 rework witnesses, the B1/B2/B3 controls, the decode-refusal witness, and the calendar-validation arms. Local corroboration: per-file claim_batch green on every touched file on this tree (7+13+44 on the last delta; full 5-file baselines green at each prior station). fleet-converge.yml regenerated only via generated_artifact_gate.dag --function main_wet.

Head lineage since the controlling review: B1–B4 repairs + transaction_nonce/run-name (e49dd85) → freshness witness split for the floor's 500ms CPU line (05e93e1) → main merges through a6d6c68d4d (785cc03) → review 57760 measure/coproduct fixes (f14021d) → decode-refusal executing witness per the lane-manager ruling (e5e9967, CI run 33365472053 SUCCESS on that head) → review 57773 fail-closed fixes: class-preserving member reads, WindowUnobserved deleted as unconstructable, dead path row deleted, Gregorian day-in-month validation (f474d96). The 7-family mutation-falsification record is in the PR comment "Mutation-falsification record…"; every mutant anchors on mechanisms byte-identical on this head.

Rework for review 5062738052 / 5063097188 (REQUEST_CHANGES) — B1–B4 + mutation evidence

  • B1 (routed health is the release/tree binding; routed window) — deployed_release_binding now consumes the ROUTED /healthz identity (revision AND surface; ReleaseSurfaceMixed blocks), and the observation window's running_release_hex/active_instance members read through the routed base (running_release_hex_routed/active_instance_text_routed); no localhost read remains on the receipt path — the local observers stay in gunbc.roadmap_launch_deployment_observe as separately named complementary diagnostics. REDs: witness_routed_surface_mixed_is_incomplete_at_release_binding, witness_route_change_during_window_is_incomplete_at_observation_window.
  • B2 (canonical repository; honest provenance split) — the receipt entry refuses BEFORE any capture unless the current run's binding names the canonical gunbc_repository.full_name AND the generated workflow file AND R; RunProvenanceObserved carries receipt_repository and the join blocks on it. The split is stated AT THE MODEL (annotation on RunProvenanceFact): three predecessor conclusions are API-read; the current run's terminal conclusion is structurally unobservable from inside itself and is an explicit POST-RUN manager verification (RLM-2b final step) — never an internal claim. RED: witness_receipt_run_in_another_repository_is_incomplete_at_run_provenance.
  • B3 (typed freshness in the structured facts) — facts_json serializes freshness as its own typed-arm object (fresh{age_seconds} | stale{age_seconds,bound_seconds} | before_deploy | instant_unparseable | cadence_unnormalizable, seconds via std.measure second_count); the round-trip witnesses recover age and bound by JSON navigation, never prose: witness_receipt_document_fresh_age_is_machine_readable, witness_receipt_document_stale_age_and_bound_are_machine_readable (split into one document each after the two-document form was budget-refused at the floor's 500ms CPU line on run 33358233304).
  • B4 (executable wet procedure) — the contradictory command block is deleted; the single authoritative sequence (below) carries expected_revision=$R on every dispatch and nonce-based run-id correlation: transaction_nonce is a generated workflow input echoed into run-name (regenerated YAML), each run id selected by its nonce in displayTitle, and the downloaded receipt's own run_id must equal the selected id. Stale structural-cadence claims removed from the deliverable map and unit_standing.dag.
  • Temporal mutation evidence — 7 defect families, one uncommitted mutant each, every one RED on exactly its discriminating witness with byte-clean restore: full record in the PR comment "Mutation-falsification record…".

Verification status — superseded record, head 9b89da837cea4ac932fb7f3ae4e2c5d17b4bbe72

Current head = the 4683c48 state below + merge of main through bfa440b66d (org-actions mode #9778, unioned in fleet_converge_workflow.dag, YAML regenerated) + dissolution of the stale cadence-residue note in unit_standing.dag (annotation-only). On THIS head: workflow run 33354805028 — all 5 checks SUCCESS; required-floor: verdict=FloorClean unexpected_failures=0 verdict_incomplete=0 non_verdict_unenrolled=0 stale_non_verdict=0; changed-witness sublane 101/101 identities standing=planned-and-passed; local per-file claim_batch 88/88 rc=0 on the merged tree; mergeable CLEAN; dashboard approvals on the head lineage (reviews 57713, 57731, 57734).

Verification status — rework record, head 4683c48b4b0b148e3722189360af8bf006f42701

Head = seven-finding rework for review 5061891290 (a2a43a139e) + merge of main through 0a6d177619 (e7d171b017) + review 57708 fixes (4683c48b4b: Microsecond/Second measure carriers, three named timer-directive readers replacing the string-tag selector, symbol citation).

CI (the evidence of record): workflow run 33349151228, headSha 4683c48b4b0b148e3722189360af8bf006f42701 — all 5 checks SUCCESS; required-floor: verdict=FloorClean unexpected_failures=0 verdict_incomplete=0 non_verdict_unenrolled=0 stale_non_verdict=0. The changed-witness sublane executed 101 identities, every one standing=planned-and-passed outcome=passed, at these per-file counts: fleet_converge_receipt_witness 17, apply_receipt_witness 6, unit_standing_witness 13, roadmap_launch_deployment_observe_witness 13, roadmap_launch_deployment_receipt_witness 39, roadmap_belt_actuate_witness 7, deployed_tree_observation_witness 4, roadmap_launch_admission_witness 1, release_binding_witness 1. That roster includes both files BuildBuddy cannot hold (observe 13, receipt 39) and all 19 rework witnesses by exact identity. Chain: reviewed head → run 33349151228 (headSha = reviewed head) → changed-witness roster → 101 exact identities → executed terminal PASS each.

Local corroboration on the same tree: per-file claim_batch (31 GiB container): 17+6+13+13+39 = 88 witnesses, rc=0 each; fleet-converge.yml regenerated by generated_artifact_gate.dag --function main_wet with only that artifact changing.

Rework red controls (added to the roster; RED is executed by fixture discrimination inside the same witnesses)

red control finding expected refusal
witness_partially_applied_exit_zero_is_incomplete_at_apply_receipt P0-2 first_blocker=apply_receipt
witness_apply_admitted_against_q_is_incomplete_at_apply_receipt P0-1 first_blocker=apply_receipt
witness_predecessor_non_success_conclusion_is_incomplete_at_run_provenance P1-4 first_blocker=run_provenance
witness_predecessor_at_another_sha_is_incomplete_at_run_provenance P1-4 first_blocker=run_provenance
witness_predecessor_on_another_workflow_is_incomplete_at_run_provenance P1-4 first_blocker=run_provenance
witness_predecessor_run_id_substitution_is_incomplete_at_run_provenance P1-4 first_blocker=run_provenance
witness_receipt_workflow_ref_not_named_is_incomplete_at_run_provenance P1-4 first_blocker=run_provenance
witness_provenance_unobserved_is_incomplete_at_run_provenance P1-4 first_blocker=run_provenance
witness_dashboard_citing_another_plan_receipt_is_incomplete_at_dashboard_receipt P1-4 first_blocker=dashboard_receipt
witness_receipt_document_facts_are_machine_readable P1-7 positive: frozen-join members recovered from structured JSON
witness_plan_receipt_with_tampered_lease_resource_fingerprint_refuses P1-5 identity refusal
witness_plan_receipt_with_tampered_lease_owner_fingerprint_refuses P1-5 identity refusal
witness_plan_receipt_with_tampered_lease_generation_refuses P1-5 identity refusal
witness_apply_receipt_partially_applied_round_trips P0-2 terminal survives the wire
witness_apply_receipt_with_unknown_terminal_wire_refuses P0-2 Unreadable
witness_dashboard_receipt_with_tampered_plan_receipt_identity_refuses P1-4 identity refusal
witness_systemd_duration_normalizes_equal_spellings P1-3 "60s" == "1min"; "2 fortnights" refuses
witness_timer_with_wrong_cadence_value_refuses P1-3 BeltTimerRefused OnUnitInactiveUSec 60000000 vs 300000000
witness_derived_timer_expectation_carries_the_emitted_cadence P1-3 expectation values from the emitted unit

Verification status — pre-rework record, head 06c2e317430b80593a4d4a0e07957d447f3fedb0

CI (the evidence of record): workflow run 33331924621 on head 06c2e317430b80593a4d4a0e07957d447f3fedb0 — all checks SUCCESS; required-floor: planned=3202 executed=3202 failed=0 … verdict=FloorClean. The changed-witness sublane prints one identity line per touched witness; all 82 read standing=planned-and-passed, at these counts: fleet_converge_receipt_witness 12, apply_receipt_witness 5, unit_standing_witness 10, roadmap_launch_deployment_observe_witness 13, roadmap_launch_deployment_receipt_witness 29, roadmap_belt_actuate_witness 7, deployed_tree_observation_witness 4, roadmap_launch_admission_witness 1, release_binding_witness 1. Chain per the reviewer bar: reviewed head → run 33331924621 (headSha = reviewed head) → changed-witness roster → 82 exact identities → executed terminal PASS each. No independent-dispatch gap remains, so no file split is needed.

BuildBuddy per-file claim_batch corroboration (one VM per file; a multi-file batch OOMs the 7.5 GB guest): fleet_converge_receipt 12/12, apply_receipt 5/5, unit_standing 10/10, each with [resolve-summary] … N witness(es) footers. The observe (13) and receipt (29) files exceed the guest at every budget; their executing route is the CI floor above.

RED-first evidence (executed red before green, each on a real run): the tamper controls asserting the unspaced JSON separator ran RED on BuildBuddy (FAIL witness_plan_receipt_with_tampered_host_refuses, FAIL witness_dashboard_receipt_with_tampered_candidate_refuses); the two document witnesses ran RED on floor run 33329794671 (returned Bool(false)); the 29 receipt witnesses ran RED on floor run 33327970268 (undefined variable: FleetConvergeYamlArtifact) — then green on 33331924621 after the named fixes. The committed controls discriminate by execution, not by construction order alone.

Generated-source provenance: .github/workflows/fleet-converge.yml regenerated by generated_artifact_gate.dag --function main_wet on this tree (local 31 GiB container; BuildBuddy cannot hold the resolve — finding 9); the regen changed only that artifact (+174/−6) and the drift gate class stands as the declared §4b rung drop.

Red-control roster (each substitutes ONE member of the otherwise-Complete population)

red control substituted fact expected first_blocker member
witness_complete_population_is_complete - -
witness_complete_receipt_document_names_its_verdict_and_identity - -
witness_plan_run_at_another_sha_is_incomplete_at_plan_receipt plan plan_receipt
witness_apply_run_at_another_sha_is_incomplete_at_apply_receipt apply apply_receipt
witness_dashboard_run_at_another_sha_is_incomplete_at_dashboard_receipt dashboard dashboard_receipt
witness_plan_run_id_substitution_is_incomplete_at_plan_receipt plan plan_receipt
witness_apply_bound_to_another_plan_is_incomplete_at_apply_receipt apply apply_receipt
witness_dashboard_bound_to_another_r_is_incomplete_at_dashboard_receipt dashboard dashboard_receipt
witness_plan_observed_on_another_host_is_incomplete_at_plan_receipt plan plan_receipt
witness_receipt_run_on_another_host_is_incomplete_at_observed_host host observed_host
witness_deployed_tree_mismatch_is_incomplete_at_deployed_tree tree deployed_tree
witness_stale_tick_is_incomplete_at_tick_standing tick tick_standing
witness_wrong_instance_tick_is_incomplete_at_tick_standing tick tick_standing
witness_wrong_revision_tick_is_incomplete_at_tick_standing tick tick_standing
witness_automatic_ready_tick_is_incomplete_at_tick_standing tick tick_standing
witness_v3_tick_on_disk_is_incomplete_at_tick_standing tick tick_standing
witness_disabled_timer_beside_fresh_tick_is_incomplete_at_unit_standing units unit_standing
witness_active_oneshot_mid_tick_is_still_complete units -
witness_wrong_principal_is_incomplete_at_principal principal principal
witness_window_change_is_incomplete_at_observation_window window observation_window
witness_transition_marker_is_incomplete_at_transition transition transition
witness_unwritable_root_is_incomplete_at_footprint footprint footprint
witness_missing_provider_credential_is_incomplete_at_provider_preflight provider provider_preflight
witness_unobservable_attempt_ledger_is_incomplete_at_workflow_endpoint workflow workflow_endpoint
witness_workflow_json_without_a_tick_is_incomplete_at_workflow_endpoint workflow workflow_endpoint
witness_desired_ref_behind_r_is_incomplete_at_desired_revision desired desired_revision
witness_two_substitutions_retain_both_blockers host -
witness_incomplete_receipt_document_carries_its_blockers principal -
witness_receipt_identity_is_stable_and_discriminating host -

RLM-2b — the wet transaction (NOT run by this PR; manager/operator only)

The executable sequence lives in ONE place — "Authorized RLM-2b sequence (manager/operator only; corrected per review 5062738052 B4)" below — with the nonce-based run-id correlation and expected_revision=$R on every dispatch. The earlier command block that stood here (R defined as this PR's merge sha; run ids via gh run list --limit 1) is deleted as contradictory to its own correction note.

Follow-up climbs from dashboard review 57765 (ruled OUT of RLM-2a scope by the lane manager; tracked here per the ruling's condition 1)

Each is a real guarantee-ladder climb on shapes consistent with current in-tree conventions; each opens a model layer ahead of its consumers, so it lands as its own change with its own witnesses. None is half-adopted in this PR — the only 57765-adjacent change here is the executing witness for the target_decision decode refusal (witness_unknown_target_decision_label_is_unreadable_not_absorbed).

climb trigger (what the follow-up must land)
systemd observed states as extdeps coproducts extdeps.systemd coproducts + wire contracts for LoadState / UnitFileState / SubState / Result (ActiveState's already exist), then ServiceUnitObserved/TimerUnitObserved parse at the boundary and the judges match arms instead of wire literals; same change internalizes the systemd.time(7) unit-spelling table as a closed SystemdTimeUnit coproduct (review 57773)
systemctl show rendering parse placement move exec_start_argv_of_show_value / show_rendered_duration_usec beside the ShowProperty operation in extdeps.systemd.systemctl, where the rendering format is cited
branded revision/tree carriers in receipt codecs GitObjectId/CommitSha constructed at the env/API boundaries (actions_run_binding.run_revision, receipt candidate_revision/candidate_tree_oid) with the four receipt codecs' identity witnesses regenerated in the same change
instant carrier for completed_at a modeled instant type (std layer) that std.types Timestamp = String aliases dissolve into — model lands before the receipt consumers adopt it

Where the ruling could NOT be satisfied by the existing model (findings, not patches)

  1. Timer cadence values are structurally checked, not compared. systemctl show TimersMonotonic renders OnBootUSec=2min; there is no systemd duration model in extdeps.systemd to ground an equality with the emitted 2min/1min. The judgement requires both entries present and the exact Unit= target. Trigger: a SystemdDuration model in extdeps.systemd with a decoder over show output.
  2. The receipt run must execute as the belt service user. The principal member compares the receipt process's effective principal (whoami) with the emitted User=; the host-pinned runner runs as the same account today, but nothing in the workflow model asserts a sudo -u — if the runner account ever differs, the member blocks (correctly) and the fix is a modeled principal switch, not a relaxation.
  3. Workflow identity is bound via GITHUB_WORKFLOW_REF (repo/path@ref), not a gh run view field — the run API exposes no path. The predicate is a prefix match on <repo>/<workflow file>@.
  4. Provider preflight selection runs Unsized (dispatch_actuator_selection(node_sizing: Unsized)) because the receipt has no work item to size; it proves the credential + provider binding of the production selection path, not a specific sizing arm.
  5. The plain live_deploy_apply_srv1_wet entry is retained beside the transaction entry for the operator's manual route; only the transaction entry is wired into the generated workflow.
  6. EXPECTED_HASH prelude on the apply job remains the pre-existing untyped shell guard; the typed admit_apply_plan_binding refusal is now the authority behind it, and the prelude is a redundancy candidate for a follow-up removal once the typed gate has one wet green.
  7. The observation window is two snapshots, opened before facts and closed after; a change strictly between two members of the fact population that reverts before close is not observed. Closing that requires a per-member timestamped read, which the fact types do not carry yet.
  8. A bare nullary artifact variant is an "undefined variable" in the floor frame. workflow_path: artifact_path(a: FleetConvergeYamlArtifact) in a bare-name witness errored at runtime for all 29 receipt witnesses; routing it through rlm_workflow_file_path() in the CLI module (where the import lives) resolved it. Same family: a free split(s:, delimiter:) call resolved on one line of a function and not five lines below inside a match-arm block (function 'split' not found in scope), and list_head(reverse(parts)) inferred Primitive(T), erasing the method surface — the parse now uses the corpus's fold idiom.
  9. fleet-converge.yml regeneration cannot run on BuildBuddy: main_wet resolve exceeds the 7.5 GB guest at every GUNBC_MEMORY_BUDGET_BYTES (12 GB → 600 MB, three kills). Regenerated locally (31 GiB container) with the freshly built binary; the drift gate (declared §4b rung drop) guards the artifact at CI.

Controlling ruling

===== SUPERSEDING RLM-2 RULING (reviewer, verbatim) =====

Ruling

The two-phase architecture is accepted, but the draft is not dispatchable verbatim. Treat the amendments below as the superseding RLM-2 gate brief.

RLM-2   OPEN
RLM-2a  AUTHORIZED TO BE CREATED under this corrected brief
RLM-2b  BLOCKED until RLM-2a is approved, merged, and R is selected

The operational shape is one modeling PR plus one wet execution transaction, not two PRs. RLM-2b changes no source and therefore has no PR of its own.

Your central decisions are right:

  • R must contain the receipt producer and machine-readable ManualReady observation; it cannot be the RLM-1 merge.
  • Existing fleet, live-deploy, belt, and serving authorities must be consumed rather than recreated.
  • A typed refusal is a valid RLM-2 result.
  • No hand-edited host state counts.
  • RLM-3 live canary activation stays out of scope.

The controlling plan requires an exact plan/apply transaction, dashboard deployment of the same revision, independent release/tree/readiness/transition/service/timer/preflight observations, and one joined RoadmapLaunchDeploymentReceipt. fileciteturn55file0

1. R is selected after RLM-2a merges, then held fixed

Do not define R in advance as “the RLM-2a merge commit.” Define it as:

The exact main revision selected after RLM-2a merges, containing its approved source, whose required CI and fleet-desired admission are used for the wet transaction.

It may happen to be the RLM-2a merge commit. If another unrelated main commit lands before the wet window, R is that later descendant or the transaction waits for a new selection.

This matters immediately: main had already advanced from the RLM-1 merge to d21370bd9526db6eac8f62fcb0af6ca04a81e1f6 during this review. fileciteturn107file0L1-L2

Once R is selected:

  1. Prove current main == R.
  2. Prove the accepted fleet-desired event names R.
  3. Independently read current refs/fleet/desired == R.
  4. Hold a short main/desired merge freeze through plan, apply, dashboard deployment, and final receipt.
  5. Every workflow invocation uses --ref R.
  6. Every run verifies its own GITHUB_SHA == R.
  7. Any main or desired advance before the final receipt invalidates the transaction and selects a new R.

FleetDesiredAcceptedRevision proves that one required-CI/default-branch event was admissible; by itself it does not prove that main and the desired ref still equal that revision at final readback. fileciteturn99file0

2. The plan/apply and dashboard transactions need typed receipts

This is the largest missing seam in the draft.

Fleet apply

The existing plan artifact is a strong authority: it carries the host/scope/member-set subject, prior generation, held lease, observed baseline, plan body, apply body, and bundle hash. fileciteturn101file0

However, fleet_converge_plan_wet and fleet_converge_apply_wet currently flatten their results to ProcessExit. The workflow’s apply job binds a prior plan run and artifact hash, but there is no durable typed apply receipt exported from that transaction. fileciteturn63file0 fileciteturn106file0

The existing ConvergeCliReceipt is not that receipt. It belongs to the separate periodic/legacy gunbc converge path and carries only:

host
applied
drifted
verdict
reason

It does not bind the reviewed plan hash, plan subject, baseline, lease generation, plan run, apply run, or executing revision. fileciteturn105file0

RLM-2a therefore adds, or factors out, exact equivalents of:

FleetConvergePlanReceipt {
  plan_run_id
  workflow_path
  run_revision: R
  observed_host
  subject
  plan_artifact_hash
  observed_baseline
  prior_generation
  planned_generation
  lease_epoch
}

FleetConvergeApplyReceipt {
  apply_run_id
  run_revision: R
  plan_receipt_identity
  plan_artifact_hash
  apply_admission: ApplyAdmitted
  generation_admission
  locked_apply_outcome
}

The apply receipt must be produced inside the typed apply composition before its CLI projection becomes ProcessExit.

Dashboard deployment

dashboard_deploy is currently an independent workflow job invoking live_deploy_apply_srv1_wet. It takes neither an expected revision nor the selected plan/apply transaction, and it emits no typed transaction receipt. fileciteturn64file0

RLM-2a must add an exact equivalent of:

LiveDeployApplyReceipt {
  dashboard_run_id
  run_revision: R
  target: srv1
  candidate_revision: R
  candidate_tree_identity
  target_decision
  apply_outcome
  readiness_outcome
}

The plan hash does not become a second eligibility authority for live deploy. R is the shared safety key. The plan/apply identity and hash ride on the dashboard receipt as provenance, so the final join cannot combine an arbitrary fleet transaction with an arbitrary dashboard transaction.

3. Correct the final receipt shape

The proposed Complete | Incomplete{first blocking member} is too lossy. It would discard valid sibling observations after the first refusal and make diagnosis depend on evaluation order.

Use this shape, or an exact typed equivalent:

RoadmapLaunchDeploymentSubject {
  rlm1_merge_commit
  rlm1_contract_digest
  revision: R
  candidate_tree_identity
  host: srv1
  active_instance
  plan_run_id
  apply_run_id
  dashboard_run_id
  receipt_run_id
}

RoadmapLaunchDeploymentFacts {
  desired_revision
  plan_receipt
  apply_receipt
  dashboard_receipt
  deployed_tree
  release_binding
  readiness
  transition
  unit_standing
  tick_standing
  footprint
  provider_preflight
  dispatch_preflight
  workflow_endpoint
  observation_window
}

RoadmapLaunchDeploymentVerdict
  = DeploymentComplete {
      subject
      facts
      receipt_identity
    }
  | DeploymentIncomplete {
      subject
      facts
      first_blocker
      further_blockers
    }

The complete arm has one private/sole production constructor that explicitly matches every positive arm and verifies all revision, host, instance, run, and identity equalities. There is no public record literal that can author DeploymentComplete.

Every independent read should still run. first_blocker is an ordered presentation projection over a nonempty blocker population, not the only retained evidence.

Both Complete and Incomplete results are serialized and persisted. The workflow exits successfully only for Complete.

4. Add the missing deployed-tree identity member

Your G1 says every member already has an existing type, but the controlling plan’s deployed tree digest does not.

The current deployed-tree authority carries:

DeployedTreeObserved {
  revision
  content: MatchesCommit | Diverged
}

DeployedTreeStanding
  = Converged
  | RevisionDrifted
  | ModifiedAtRevision
  | Unobserved

It does not carry a root-tree object identity. fileciteturn85file0

Add G7 within the existing DeployedTreeLocus and transport:

  • derive candidate root-tree object ID from R;
  • remotely read the deployed repository’s HEAD^{tree} through the same sealed srv1 locus;
  • carry that object ID in the deployed-tree observation;
  • require candidate tree OID equals deployed tree OID;
  • also require DeployedScopeMatchesCommit.

This is an additional argv on the existing typed observer, not a second remote-revision transport.

deployed_tree_report_ci_wet remains only a renderer/CLI edge. The deployment receipt consumes the typed observation and standing directly; it must never parse the report text. fileciteturn77file0

5. Health and workflow evidence must be actual live HTTP observations

Two entries in the authority map currently name renderers as though they were observers:

  • healthz_body_with_release_identity constructs the expected body; it is not evidence that the routed service returned it.
  • serve_workflow_response_for_instance constructs the route response; calling it in the receipt process would not prove the deployed public route served those bytes.

The final receipt mode must execute live GETs against the production endpoint and type the results:

GET /healthz
  → HealthzEffectiveRead
  → observe_running_release_identity
  → DeployedReleaseBinding
  → require ReleaseBoundToTree at R and expected surface

GET /workflow.json
  → status + body observation
  → parsed roadmap-workflow schema
  → workflow attempt standing
  → exact embedded tick standing

The running-release parser validates both revision and surface identity, and DeployedReleaseBinding independently joins the process announcement to the deployed tree. fileciteturn82file0 fileciteturn79file0

The /workflow.json parser must not treat HTTP 200 as sufficient. The current wire can return a valid workflow document while its nested belt_tick is absent or unreadable; those states must refuse RLM-2 rather than become “Idle.” The route currently embeds the persisted tick receipt as a typed Present/Absent/Unreadable standing. fileciteturn92file0 fileciteturn97file0

Also observe /instance.json or its exact existing typed equivalent. The active routed instance must equal the instance named by the tick, unit standing, footprint, provider preflight, and receipt path.

6. G2 becomes a bound and fresh tick receipt, not only spawn_mode

Bumping the current tick receipt with one string field is insufficient. The current v3 receipt contains observed_at, launch identities, and four pass outcomes, but no instance, mode, deployed revision, or receipt identity. fileciteturn92file0

RLM-2a should bump the schema and add a typed execution standing:

BeltTickExecutionStanding
  = TickExecuted {
      instance_id
      deployed_revision
      spawn_mode
    }
  | TickExecutionWithheld {
      refusal
    }

BeltTickReceiptV4 {
  receipt_identity
  observed_at
  execution
  launches
  spawn_pass
  teardown_pass
  verify_pass
  publish_pass
}

For RLM-2 Complete:

instance_id       == active production instance
deployed_revision == R
spawn_mode        == ManualReady
receipt observed  after dashboard deployment completed
receipt age       within a cadence-derived bound

An old v3 receipt refuses. A v4 receipt from another instance, revision, mode, or pre-deployment timestamp refuses.

/workflow.json projects this exact receipt and identity. It does not derive mode from roadmap_belt_production_spawn_mode.

The wet procedure waits for a natural timer-triggered tick after dashboard deployment. Manually invoking belt_run_once would prove that the service can run, not that the timer is active.

7. Q2: G4 is mandatory, but model the correct systemd states

G4 remains in scope. Readiness plus a fresh tick cannot prove the timer is enabled now: a service can be invoked manually, write one fresh receipt, and sit behind a disabled timer.

The controlling plan independently requires service/timer state. fileciteturn55file0

Do not model “service and timer are both enabled and active,” because the emitted units deliberately have different semantics:

  • dashboard serve service: Type=simple;
  • belt service: Type=oneshot;
  • belt timer: enabled under timers.target, targeting the oneshot service, with OnBootSec=2min, OnUnitInactiveSec=60s, and AccuracySec=5s. fileciteturn75file0

The positive unit standing is therefore:

dashboard service:
  loaded
  enabled
  active
  effective ExecStart/User/WorkingDirectory match R's emitted unit

belt timer:
  loaded
  enabled
  active/waiting
  targets the exact belt service
  effective cadence matches R's emitted unit

belt oneshot service:
  loaded
  static/not separately enabled
  exact ExecStart/User/WorkingDirectory
  most recent result success
  ExecMainStatus == 0
  normally inactive between ticks is ACCEPTED

Add the smallest typed systemctl show / system-scope is-enabled observer needed. The extdeps surface currently models IsActive, while its own note says there is no modeled system-scope IsEnabled operation. fileciteturn72file0

The discriminating positive control is important: a correctly completed inactive oneshot must remain green.

8. Bind every ambient preflight to srv1 and the service principal

The current workflow’s plan/apply jobs run on generic [self-hosted, ARM64]. The host=srv1 input does not itself select srv1; fleet_converge_plan_wet observes the local kernel hostname and constructs the plan subject from that host. fileciteturn62file0 fileciteturn106file0

RLM-2a must make one of these true:

  • select an exact srv1 runner label; or
  • execute through the existing srv1 SSH locus.

In either case, the typed plan receipt records the observed host and refuses unless it is srv1. Artifact naming from the workflow input is not host evidence.

The same applies to footprint and provider observations. belt_footprint_admission_for_instance deliberately states that writability must be tested as the effective principal that will perform dispatch, not as a privileged deploy or runner account. fileciteturn92file0

The receipt must therefore prove:

observed host       == srv1
effective principal == emitted belt ServiceUser
instance             == active routed instance

Then run:

  • belt_footprint_admission_for_instance;
  • belt_provider_preflight_for_instance for the exact provider selected by production;
  • dispatch_preflight_for_instance.

DispatchPreflightReport remains complementary: its source explicitly says provider authentication is not one of its axes. It cannot substitute for BeltProviderPreflight. fileciteturn95file0

9. Bind the four workflow runs and prevent mixed snapshots

The frozen transaction has four, not two, workflow runs:

  1. plan;
  2. apply;
  3. dashboard deploy;
  4. final deployment receipt.

The desired-admission workflow run is additional provenance.

Every run/artifact binding must verify:

repository
workflow path
run id
run head SHA == R
successful conclusion where required
expected predecessor receipt identity

The current apply job already downloads one exact plan run and checks the bundle hash; preserve that mechanism and add source-revision and typed-receipt binding. fileciteturn63file0

Apply, dashboard deploy, and final readback must share one srv1 production mutation/convergence concurrency domain, or an equivalent modeled host lease. Today plan/apply and dashboard deploy have separate concurrency groups and may overlap. fileciteturn62file0 fileciteturn64file0

The final readback additionally observes at both the beginning and end:

main
refs/fleet/desired
deployed revision/tree
running release
transition standing
active instance

A change during capture produces DeploymentIncomplete { blocker: ObservationWindowChanged }, not a self-consistent join assembled from two production moments.

10. Q1: persist exact bytes on the host and as a workflow artifact; do not commit them

Artifact-only with 30-day retention plus a manager-recorded identity is insufficient. The current workflow’s plan artifact retention is 30 days. fileciteturn62file0

Do not commit the wet receipt to main. That would create a new main revision after R and immediately invalidate the exact equality the receipt is supposed to freeze. A production observation is also not source authority.

Required durability:

  • serialize one canonical receipt document;
  • derive its modeled structural identity;
  • compute SHA-256 over the exact serialized bytes;
  • write those bytes atomically to a content-addressed, no-overwrite path beneath the modeled per-instance receipt root;
  • upload those exact same bytes as a GitHub run artifact with the maximum available retention;
  • have the manager verify host copy and workflow artifact share the same SHA-256.

The existing per-instance receipt root is already modeled by instance_receipts_dir; add a dedicated content-addressed deployment-receipt path below it. fileciteturn104file0

Incomplete receipts are persisted too. A refusal is evidence, not discarded output.

11. Q3: the RLM manager/operator dispatches RLM-2b

gh workflow run is an acceptable transport. There is no requirement to use the GitHub web UI.

The implementation worker for RLM-2a may prepare the exact commands and evidence template, but it may not autonomously actuate production. After RLM-2a merges and R is selected, the RLM manager under the operator’s authority dispatches the serial transaction.

A delegated worker dispatch would require a separate one-shot authorization naming:

R
host=srv1
workflow path
mode sequence
plan run/hash
apply run
dashboard run
receipt run

Absent that exact grant, dispatch remains manager/operator-only.

Superseding RLM-2a acceptance bar

The RLM-2a work item may now be created with these required deliverables:

  1. The typed plan/apply and dashboard transaction receipts.
  2. RoadmapLaunchDeploymentSubject, complete fact population, and total verdict.
  3. Deployed candidate/root-tree object identity readback.
  4. Belt tick receipt v4 with instance/revision/mode/identity/freshness.
  5. Exact systemd service/timer standing.
  6. Live /healthz, /instance.json, and /workflow.json observers and decoders.
  7. Exact srv1/effective-principal binding for ambient preflights.
  8. Revision/run/artifact bindings and shared srv1 transaction concurrency.
  9. Durable content-addressed receipt persistence plus workflow artifact.
  10. Generated rlm_launch_deployment_receipt mode emitted from gunbc.fleet_converge_workflow; generated YAML is regenerated, never hand-edited.

The red controls land first and exercise the exact production completion fold. In addition to your seven controls, include:

  • plan, apply, dashboard, or receipt run at a SHA other than R;
  • plan run ID/hash substitution;
  • apply receipt bound to another plan;
  • dashboard receipt bound to another R;
  • workflow input srv1 while observed runner host is not srv1;
  • candidate/deployed root-tree OID mismatch;
  • v3, stale, wrong-instance, wrong-revision, or non-ManualReady tick receipt;
  • disabled timer beside an otherwise fresh manually fabricated tick;
  • correctly inactive-successful oneshot service as a positive control;
  • wrong effective principal;
  • production state changing during the observation window.

The destructive falsifiers—tree mutation, unwritable root, credential removal, and transition marker—run synthetically, hermetically, or against a disposable locus. Do not poison srv1 to demonstrate them.

Existing member witnesses are supporting evidence. The new load-bearing controls each replace one member in an otherwise Complete fact population and prove the deployment join becomes Incomplete with that member named.

Authorized RLM-2b sequence (manager/operator only; corrected per review 5062738052 B4)

R is the exact admitted MAIN revision the operator selects AFTER this PR merges — possibly a later descendant of the merge commit, whatever main revision the operator rules the transaction installs and proves. Every dispatch carries expected_revision=$R; every run of the transaction refuses unless it checked out exactly R. Run-id correlation uses a transaction NONCE: the operator mints one, passes it as the transaction_nonce input, the workflow echoes it into run-name, and each run id is then selected by matching the nonce in the run's displayTitle — never by gh run list --limit 1. The downloaded receipt's own run_id must equal the selected run id, closing the loop.

R=<operator-selected admitted main revision, chosen after merge>
NONCE=rlm2b-$(date -u +%Y%m%dT%H%M%SZ)-$RANDOM
W=fleet-converge.yml
by_nonce () { gh run list --workflow $W --json databaseId,displayTitle \
  --jq ".[]|select(.displayTitle|contains(\"$1\"))|.databaseId" | head -1; }

# 1. plan (nonce N1)
gh workflow run $W -f host=srv1 -f mode=plan -f expected_revision=$R -f transaction_nonce=$NONCE-plan
# wait for completion, then:
PLAN=$(by_nonce $NONCE-plan)   # confirm: plan receipt in artifact names run_id=$PLAN
HASH=<plan bundle digest printed by the plan step of run $PLAN>

# 2. apply (nonce N2)
gh workflow run $W -f host=srv1 -f mode=apply -f expected_revision=$R -f transaction_nonce=$NONCE-apply \
  -f plan_workflow_run_id=$PLAN -f plan_artifact_hash=$HASH
APPLY=$(by_nonce $NONCE-apply) # confirm: apply receipt names run_id=$APPLY and terminal=fully_applied

# 3. dashboard deploy (nonce N3)
gh workflow run $W -f host=srv1 -f mode=dashboard_deploy -f expected_revision=$R -f transaction_nonce=$NONCE-dash \
  -f plan_workflow_run_id=$PLAN -f apply_workflow_run_id=$APPLY
DASH=$(by_nonce $NONCE-dash)   # confirm: dashboard receipt names run_id=$DASH

# 4. receipt join (nonce N4)
gh workflow run $W -f host=srv1 -f mode=rlm_launch_deployment_receipt -f expected_revision=$R -f transaction_nonce=$NONCE-rcpt \
  -f plan_workflow_run_id=$PLAN -f apply_workflow_run_id=$APPLY -f dashboard_workflow_run_id=$DASH
RCPT=$(by_nonce $NONCE-rcpt)

# 5. manager verification AFTER the receipt run completes (the half the receipt cannot see):
gh run view $RCPT --json conclusion   # must be success; the receipt run cannot observe its own terminal conclusion
# download artifact rlm-launch-deployment-receipt from $RCPT; verdict must be DeploymentComplete.

Provenance split, stated precisely (review 5062738052 B2): inside the receipt run, RunProvenanceFact carries the three PREDECESSOR runs' API-read conclusions/head_sha/path plus the CURRENT run's binding admitted against the canonical repository, the generated workflow path, and R — the current run's own terminal conclusion is structurally unobservable from inside itself, and is verified by the manager in step 5 after completion. The receipt does NOT claim four conclusions.

Frozen RLM-2 join

The final join expands to:

R
RLM-1 contract digest
candidate root-tree object identity
deployed root-tree object identity
RoadmapLaunchDeploymentReceipt identity
receipt byte SHA-256
durable host receipt path
receipt workflow run id
plan workflow run id
plan artifact hash
plan subject + lease epoch
apply workflow run id
FleetConvergeApplyReceipt identity
dashboard workflow run id
LiveDeployApplyReceipt identity
active instance identity
fresh BeltTickReceipt identity
observed spawn mode = ManualReady

RLM-3 remains closed until that exact tuple is accepted.

Brian Searls and others added 10 commits August 30, 2026 16:22
…unchDeploymentReceipt, root-tree OID readback, BeltTickReceipt v4, systemd unit standing, live observers, run/artifact bindings, content-addressed persistence, generated receipt mode

Red controls and models land together in this first commit; the generated
fleet-converge.yml regeneration follows in the next commit once the remote
regen dispatch reports (the local gunbc binary is stale and cannot check
this tree).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
…h SystemdServiceDirective; hoist a body annotation to item grain

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
…h the emitted ": " separator

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
…; remaining ListHeadResult arms

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
…r reverse loses the element type)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
…nnotation form; new note rows become §4c annotations

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
…low_file_path (a bare nullary artifact variant is an undefined variable in the floor frame)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
…low (rlm_launch_deployment_receipt mode, receipt uploads, shared host-mutation concurrency)

Regenerated via generated_artifact_gate main_wet on this tree; only the
fleet-converge artifact changed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 30, 2026 20:51

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES — exact head 06c2e317430b80593a4d4a0e07957d447f3fedb0 reviewed.

I accept the execution evidence on this head: CI run 33331924621 is head-bound and green; the floor reports 3202 planned / 3202 executed / 0 failed; and the 82 changed witness identities, including the 42 floor-only identities, have terminal planned-and-passed evidence. I also confirm that this is substantial modeling rather than a shell wrapper: the 18-member total completion fold, sole-constructor DeploymentCompleteProof, same-locus G7 root-tree readback, BeltTickReceipt v4, shared host-mutation concurrency, and content-addressed persistence are real.

The head is nevertheless not safe to merge. These are production-boundary defects, not missing corroboration:

  1. P0 — fleet apply can mutate srv1 at a revision other than R. fleet_converge_apply_step does not pass RLM_EXPECTED_REVISION, and fleet_converge_apply_wet never calls read_expected_revision / admit_run_revision before run_shell_commands reaches fleet_converge_locked_apply_script. It proves only that the plan and apply receipts name the same SHA. A plan and apply both run at Q can therefore agree and actuate while the operator selected R; the final receipt would discover the wrong SHA only after mutation. Pass the independent expected R into apply (and bind every run as ruled), refuse before the locked actuator, carry the admission in the typed receipt, and add a RED-first control proving Q/Q with expected R cannot reach apply.

  2. P0 — PartiallyApplied can be certified as a successful fleet apply. The existing fleet model deliberately distinguishes FullyApplied from PartiallyApplied and deliberately does not change the shell exit code for sibling-axis refusals. The new apply receipt carries only locked_apply_exit_code; the completion fold admits exit code 0. Thus a refused axis plus an exit-0 partial application can reach DeploymentComplete. Carry the typed apply terminal and the relevant apply/generation admissions in FleetConvergeApplyReceipt (or an exact equivalent), require FullyApplied, and add the discriminating exit-0/PartiallyApplied RED.

  3. P1 — timer cadence is not matched to R's emitted unit. TimerUnitExpectation contains only the target unit; judge_belt_timer merely checks that TimersMonotonic contains the two directive names. Any values pass, and AccuracySec is not checked. Separately, tick freshness authors another literal 60 seconds while claiming derivation from emission. The ruling requires effective cadence matching R. Add a normalized systemd duration/effective-timer model, derive unit expectations and freshness from the same emitted authority, compare at least OnBootSec, OnUnitInactiveSec, and AccuracySec (or their exact effective equivalents), and add a wrong-cadence-beside-fresh-tick RED. A declared residue does not amend this acceptance bar.

  4. P1 — the four-run provenance chain is incomplete. The final receipt run verifies its SHA but does not prove its own GITHUB_WORKFLOW_REF names the generated workflow; its subject adopts run.repository as the expected repository and writes the expected path without comparing the current run to either. No run conclusion is carried or verified. Dashboard provenance names plan/apply run IDs and the plan hash, but not the exact predecessor plan/apply receipt identities. Bind the canonical repository, current receipt workflow path, successful conclusions, and predecessor receipt identities for all four runs, with wrong-repository/path/conclusion/predecessor RED controls.

  5. P1 — the plan receipt truncates the ruled lease epoch. LeaseEpoch is {lease_key, resource_fingerprint, owner_fingerprint, generation}; FleetConvergePlanReceipt serializes only lease_key plus generation projections. The frozen RLM-2 join therefore cannot name the actual held epoch. Carry the whole typed epoch (or an injective exact equivalent) in the receipt identity and wire form, and add member-substitution/tamper controls.

  6. P1 — the HTTP evidence bypasses the production route. All three observers construct http://127.0.0.1:<port>/.... That proves the local process, not that the deployed production/Tailscale route serves the release and active instance. A broken or misdirected route can coexist with a healthy localhost and still reach Complete. Derive the routed endpoint from the existing deployment/network authority, observe /healthz, /instance.json, and /workflow.json through it, and add a local-healthy/routed-wrong RED.

  7. P1 — the durable receipt does not serialize the claimed machine-readable fact population. Both verdict arms emit facts as an array of rendered strings, and the receipt identity hashes delimiter-joined presentation text. The PR's own wet template addresses .facts.tick_standing, .facts.unit_standing, and .facts.observation_window; none of those paths exists. Serialize a structured fact object preserving typed arms and load-bearing payloads, derive identity from that canonical structure, and keep any prose lines as a separate presentation projection.

Also correct the wet template before merge: R is selected after RLM-2a merges and may be a later admitted main descendant; it is not definitionally this PR's merge commit. Do not discover run IDs with an uncorrelated gh run list --limit 1 race.

Ruling: no approval on this head; do not merge. RLM-2b remains blocked and no production dispatch is authorized. Bring a new exact head with RED-first evidence for the new discriminators, regenerated YAML from gunbc.fleet_converge_workflow, and exact-identity floor execution for every affected witness. A dashboard review does not discharge these findings.

…unit blocker matches recover WHICH unit refused; verdict matched at its one consumer); Scaffold+DissolutionCondition pair for gunbc_ci_fleet_key_agent_script with the marker on the emitted runner; regenerate fleet-converge.yml

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
@gunbai-bot

gunbai-bot Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor Author

Both findings of review 57664 addressed at 7382d27:

  1. Predicate dissolution: launch_unit_standing_holds and verdict_is_complete are deleted. unit_standing_blockers now matches each unit's standing in place — recovering what the Bool discarded: the blocker carries WHICH unit refused and its own rendering — and the CLI's exit projection matches the verdict coproduct directly at its single consumer (the codex_preflight_ok precedent from review 44110).
  2. The fleet key-agent runner now carries the required pair in gunbc.ci_spec (gunbc_ci_fleet_key_agent_shell_emit_scaffold, …_dissolution_trigger naming the orchestration-to-shell bash-emission capability, General orchestration intent to Bash emit fold over grammar rows #5828 / shell→intent Phase 2), and the EMITTED runner's first line is the # 🟡 dissolve-on: … marker — present in both regenerated occurrences in .github/workflows/fleet-converge.yml, same convention as ci_release_bins_pack_script. Note the runner itself pre-dates this PR (the receipt job is its third consumer); the marker now covers all of them.

fleet-converge.yml regenerated via generated_artifact_gate main_wet on this tree.

— sent from crisp-newt-85

Brian Searls and others added 3 commits August 30, 2026 21:20
…5; mode options union; regenerate fleet-converge.yml

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
…y, required FullyApplied terminal, normalized timer cadence values from the emitted unit, four-run provenance, whole LeaseEpoch on the plan receipt, routed observers, structured facts serialization

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh

# Conflicts:
#	dag/gunbc/fleet/fleet_converge_plan_cli.dag
@gunbai-bot

gunbai-bot Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

Rework for review 5061891290 (REQUEST_CHANGES on 06c2e31) is on head e7d171b017b5c325e767b1c378163b378e012120 (includes a merge of main through 0a6d177619). All seven findings addressed; the PR body's "Rework for review 5061891290" section carries the full map and the added red-control roster. In brief:

  • P0-1: RLM_EXPECTED_REVISION is read and admitted (read_expected_revision → admit_run_revision) in BOTH fleet_converge_plan_wet and fleet_converge_apply_wet before any observation or actuation — fleet_converge_locked_apply_script is unreachable at Q≠R — and the admitted revision is carried on the apply receipt (expected_revision_admitted, identity + wire). Workflow env regenerated, never hand-edited.
  • P0-2: FleetConvergeApplyTerminal (FullyApplied | PartiallyApplied{refused_axis_count, detail}) is carried on the plan artifact and both fleet receipts; the join requires FullyApplied — RED witness_partially_applied_exit_zero_is_incomplete_at_apply_receipt (PartiallyApplied under exit 0 → first_blocker=apply_receipt).
  • P1-3: extdeps.systemd systemd_duration_usec (systemd.time(7) normalization to usec); TimerUnitExpectation gains the three cadence VALUES derived from R's emitted timer unit, and the freshness bound derives from the same emitted belt_tick_cadence (one authority); judge_belt_timer compares normalized values — RED witness_timer_with_wrong_cadence_value_refuses.
  • P1-4: subject.repository from gunbc_repository.full_name; per-predecessor readback via workflow_runs.GetRun (conclusion=success, head_sha=R, path=subject.workflow_path, exact run_id); receipt run's GITHUB_WORKFLOW_REF must name the generated workflow; dashboard provenance carries the exact plan/apply receipt identities, recomputed by the join — six run_provenance REDs plus the dashboard-identity RED.
  • P1-5: whole LeaseEpoch (resource_fingerprint, owner_fingerprint, generation beside lease_key) on the plan receipt, identity-bearing — three per-member tamper REDs.
  • P1-6: /healthz, /instance.json, /workflow.json observed through the routed production endpoint derived from deployment_tailnet_url(deployment_spec_srv1()); localhost remains only the complementary release-binding probe; underivable route is a typed refusal, never a fallback.
  • P1-7: facts_json serializes every facts member with its typed arm; the receipt identity hashes subject + that canonical JSON; prose lines are presentation only — witness_receipt_document_facts_are_machine_readable recovers the frozen-join members from the document without parsing prose.

Both wet-template corrections adopted in the PR body: R is the operator-selected admitted main revision after merge (not definitionally this PR's merge commit), and predecessor run ids come from receipt-bound artifacts, never gh run list --limit 1. Floor evidence chain for this exact head will be recorded once run 33347688623 concludes.

…nd tick freshness, three named timer-directive readers replace the string-tag selector, symbol citation replaces the line-range citation

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
@gunbai-bot

gunbai-bot Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

Response to review 57708 (dashboard artifact /api/reviews/57708/artifacts/stdout.log), addressed on head 4683c48b4b0b148e3722189360af8bf006f42701:

  • Duration as bare Int (unit_standing / systemd) — fixed. extdeps.systemd systemd_duration_usec now returns Microsecond? (std.measure Measure<Time, Micro, Nat>, the same carrier gunbc.spark.serving_boot_provenance uses for systemd monotonic readings; Int→Nat crossed through std.checked_arithmetic checked_int_magnitude, never by clamp). TimerUnitExpectation.on_boot_usec/on_unit_inactive_usec/accuracy_usec are Microsecond; judge_belt_timer compares counts and prints them via microsecond_count. SystemdTimeSpanPart.value stays Int deliberately: it is the pre-unit lexical half of a (value, unit-spelling) pair — the unit is the sibling field, so a Measure carrier there would assert a scale the parser has not yet resolved.
  • Tick freshness ages — same fix: TickFresh/TickStale carry Second (age_seconds/bound_seconds), the cadence and bound derivations return Second?, and a now-before-tick instant now refuses (TickInstantUnparseable) instead of flowing a negative age into an unsigned carrier.
  • String-tag selector — fixed. timer_directive_duration_usec(directives, which: String) is deleted; three named readers (timer_on_boot_duration, timer_on_unit_inactive_duration, timer_accuracy_duration) each match their own directive constructor.
  • Positional citation — fixed. fleet_workflow_steps.dag now cites (gunbc.fleet_converge_workflow fleet_converge_job) instead of the line range.
  • ci_spec *_timeout_minutes bare Int — NOT REPRODUCIBLE against the current head: no symbol matching timeout_minutes (nor gunbc_ci_rlm_launch_deployment_receipt_job_backstop_timeout_minutes) exists in dag/gunbc/ci/ci_spec.dag, and the budget arithmetic there is already carried in the std.measure Minute type (gunbc_ci_workflow_wrapper_budget_minutes() -> Minute). If the finding was against another symbol, please name it.

— sent from crisp-newt-85

@gunbai-bot

gunbai-bot Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

Final verification chain for head 4683c48b4b0b148e3722189360af8bf006f42701 (promised in the review 5061891290 and review 57708 responses above):

  • Run 33349151228 (workflow witnesses) — headSha 4683c48b4b0b148e3722189360af8bf006f42701, all 5 checks SUCCESS.
  • required-floor: verdict=FloorClean unexpected_failures=0 verdict_incomplete=0 non_verdict_unenrolled=0 stale_non_verdict=0.
  • Changed-witness sublane: 101 identities, each printed standing=planned-and-passed disposition=planned_as_changed_witness outcome=passed — fleet_converge_receipt 17, apply_receipt 6, unit_standing 13, roadmap_launch_deployment_observe 13, roadmap_launch_deployment_receipt 39, roadmap_belt_actuate 7, deployed_tree_observation 4, roadmap_launch_admission 1, release_binding 1. This includes both files that exceed the BuildBuddy guest (observe 13, receipt 39) and all 19 rework witnesses by exact identity (the two P0 discriminators witness_apply_admitted_against_q_is_incomplete_at_apply_receipt and witness_partially_applied_exit_zero_is_incomplete_at_apply_receipt among them).
  • Local corroboration on the same tree: per-file claim_batch, 88/88 witnesses rc=0; fleet-converge.yml regenerated via generated_artifact_gate.dag --function main_wet, only that artifact changed.

Discrimination evidence for the rework controls: each control substitutes exactly one member of the otherwise-Complete fixture population and asserts the typed Incomplete verdict naming that member as first_blocker (e.g. PartiallyApplied under exit 0 → apply_receipt; expected R against a run at Q → apply_receipt; each predecessor-run substitution → run_provenance), with the untouched positive control Complete in the same file — executed red-arm and green-arm on this head, in CI and locally. The pre-rework RED-first run record (33327970268, 33329794671, BuildBuddy FAIL lines) stands in the PR body.

— sent from crisp-newt-85

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES — exact head 4683c48b4b0b148e3722189360af8bf006f42701 re-reviewed.

I accept the head-bound execution evidence: run 33349151228 has five successful jobs on this SHA, including required build, required floor, Rust unit tests, witnesses, and fabric evidence. I also accept that the following prior findings are substantively repaired in code: expected-R admission now dominates plan/apply and the locked actuator; exit-zero PartiallyApplied is rejected by the completion fold; timer values are normalized and compared against the emitted unit; the full LeaseEpoch is identity-bearing; and dashboard provenance now binds the exact downloaded plan/apply receipt identities.

The head is still not mergeable. Three of the seven prior findings are only partially repaired, the wet procedure remains contradictory, and the required temporal falsification evidence is still absent.

  1. P1 — routed /healthz is still not the release/tree binding, and the observation window remains local. In rlm_launch_deployment_receipt_bound, both healthz = observe_healthz(port) and healthz_routed are read, but deployed_release_binding(observation: tree, identity: ...) consumes the LOCAL health identity. The routed result feeds only ReadinessFact, whose blocker compares revision but discards surface. Thus a routed endpoint serving R under the wrong surface can pass while localhost supplies the expected surface/tree join. The opening and closing window_snapshot likewise call local running_release_hex(port) and active_instance_text(port), so a route change during capture is invisible. Make routed health the load-bearing DeployedReleaseBinding input, require its expected surface, and make the window's running-release/active-instance members routed. Keep localhost only as a separately named complementary observation. Add the previously required local-healthy/routed-wrong RED and a routed-state-changed-during-window RED.

  2. P1 — current receipt-run provenance still does not prove the canonical repository, and “four conclusions carried” overclaims the implementation. The three predecessor runs are API-read and checked well. The current run is represented only by receipt_workflow_ref_names_path. run_binding_names_workflow_file builds its prefix from the binding's OWN repository, so fork-owner/gunbc/.github/workflows/fleet-converge.yml@... passes; no blocker compares run.repository with gunbc_repository.full_name. Carry or admit the current run binding against canonical repository + workflow path + R before capture, with a wrong-current-repository RED. The receipt run cannot observe its own terminal conclusion from inside itself; that is acceptable only as an explicit RLM-2b manager verification after the run completes, not as a claim that RunProvenanceFact carries all four conclusions. Correct the model/body/evidence template to state the split precisely, or add a post-run attestation mechanism.

  3. P1 — facts is structured overall, but tick freshness is still presentation text. facts_json serializes tick_standing.freshness as json_string(tick_freshness_text(fr)); it does not preserve the TickFresh | TickStale | TickBeforeDeploy | TickInstantUnparseable | TickCadenceUnnormalizable arm or the age/bound payloads. The machine-readable witness checks execution revision/mode but not freshness. Serialize freshness as a typed-arm object with its load-bearing fields, and extend the round-trip/navigation witness to recover the observed age and cadence-derived bound without parsing prose.

  4. P1 — the PR body's executable wet procedure still contradicts its appended correction. The retained command block says R=<merge sha of this PR>, omits expected_revision=$R from both plan and apply even though those modes now require it, and still discovers PLAN/APPLY/DASH/RCPT through uncorrelated gh run list --limit 1. The later prose saying the opposite does not repair executable instructions. Replace or delete the stale block. Supply a genuinely correlation-safe run-ID mechanism; “read the run ID from the receipt-bound artifact” is circular because downloading that artifact already requires its run ID. A transaction nonce carried in workflow input/run identity/receipt is one sound shape. Also remove the now-false timer-cadence residue text in the PR body and unit_standing.dag; values are no longer structural-only.

  5. The temporal RED-first bar remains outstanding. Exact-head substitution witnesses are valuable and I accept their current green discrimination, but they do not establish that the newly added tests failed without the repairs. The old temporal reds exercised the original control population, not these seven new discriminators. Before approval, run mutation falsification against temporary refs/trees (never production): one mutant per repaired defect family is sufficient, not one per witness. At minimum prove failure when (a) the pre-actuation expected-R admission is removed, (b) PartiallyApplied is admitted, (c) timer value comparison is relaxed, (d) current/predecessor provenance or receipt-identity binding is relaxed, (e) one LeaseEpoch member is dropped, (f) localhost is substituted for routed authority, and (g) typed freshness is collapsed to prose. Record mutant SHA/tree, exact failing witness identities, and then the final-head green executions. These mutation runs may occur after the repair commit; they are the accepted equivalent of having landed each RED first.

Ruling: no approval on 4683c48b4b0b148e3722189360af8bf006f42701; do not merge. RLM-2b remains blocked and no production dispatch is authorized. Bring a new exact head with the three completion seams closed, the actual wet block corrected, generated YAML regenerated, exact-identity floor green, and the mutation-falsification receipts. Dashboard approval does not discharge these findings.

Brian Searls and others added 2 commits August 31, 2026 03:26
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh

# Conflicts:
#	.github/workflows/fleet-converge.yml
#	dag/gunbc/fleet/fleet_converge_workflow.dag
…ed via systemd_duration_usec since review 5061891290 P1-3

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES — exact head 9b89da837cea4ac932fb7f3ae4e2c5d17b4bbe72 re-reviewed. This supersedes the head anchor of my review on 4683c48b4b0b148e3722189360af8bf006f42701 without changing its substantive ruling.

I verified the update. The branch-local RLM delta is the merge of current main, including the allocation-store and organization-actions changes with regenerated fleet-converge.yml, followed by an annotation-only commit deleting the superseded timer-cadence residue. I accept that timer-values-have-no-model prose as closed. I also accept the new head-bound execution evidence: workflow run 33354805028 contains five successful jobs on this exact SHA, and the reported floor/changed-witness evidence re-establishes the prior final-head green population.

My verdict on 4683c48b was CHANGES_REQUESTED, not APPROVE. None of the remaining completion seams is changed by this head update:

  1. Routed observation is still not the load-bearing release/tree binding, and the observation window remains local. rlm_launch_deployment_receipt_bound reads both localhost and routed health, but deployed_release_binding still consumes the localhost health identity. Routed health supplies only ReadinessFact; that blocker compares revision while discarding the routed surface. The opening and closing window_snapshot likewise obtain running release and active instance through localhost. A healthy local process can therefore supply the expected surface/tree join while the production route serves R under a wrong surface, and a route change during capture is not a window change. Make routed health the binding input, require its expected surface, make the window's running-release and active-instance observations routed, keep localhost as a separately named complementary fact, and add local-healthy/routed-wrong plus routed-window-change controls.

  2. The current receipt run is still not admitted against the canonical repository, and the claimed four-conclusion chain remains overstated. The three predecessor API records are checked well. For the current run, however, RunProvenanceFact carries only receipt_workflow_ref_names_path; run_binding_names_workflow_file derives its prefix from the binding's own repository. A fork repository using the same workflow path can satisfy it, and no blocker compares the current run.repository with gunbc_repository.full_name. Admit/carry the current binding against canonical repository, workflow path, run id, and R before capture, with a wrong-current-repository control. The current run's own terminal conclusion cannot be known inside that run; model the split honestly and require a post-run manager attestation/check, or add a later attestation mechanism.

  3. Tick freshness is still presentation text inside the otherwise structured facts object. facts_json serializes tick_standing.freshness through tick_freshness_text(fr) as a JSON string. It does not preserve the TickFresh | TickStale | TickBeforeDeploy | TickInstantUnparseable | TickCadenceUnnormalizable arm or the age/bound payloads. Serialize freshness as a typed-arm object with unit-bearing load-bearing fields, and extend the machine-readable navigation/round-trip witness to recover the freshness arm, age, and cadence-derived bound without parsing prose.

  4. The executable wet procedure in the PR body is still contradictory and correlation-unsafe. The retained block still says R=<merge sha of this PR>, omits expected_revision=$R from plan and apply despite both modes requiring it, and assigns PLAN/APPLY/DASH/RCPT with uncorrelated gh run list --limit 1. The appended correction prose does not repair executable commands. Replace or delete that block and use a genuinely correlation-safe identity, such as a transaction nonce carried from dispatch input through API-visible run identity and typed receipts. Reading a run id from its artifact is circular because the run id is already needed to download the artifact.

  5. The temporal RED-first bar remains outstanding. I accept the exact-head substitution witnesses as valuable identity-grain discrimination, but they do not show that the newly added controls failed without the repaired mechanisms. Execute the offered non-production mutation runs before approval. One mutant per defect family is sufficient: expected-R dominance, PartiallyApplied, timer-value equality, provenance/receipt identity, one LeaseEpoch member, routed-versus-local authority, and structured freshness. Record mutant commit/tree, exact failing witness identities, and the restored final-head green executions.

Ruling: no approval on 9b89da837cea4ac932fb7f3ae4e2c5d17b4bbe72; do not merge. RLM-2b remains blocked and no production dispatch is authorized. Bring a new exact head closing the three semantic seams, replacing the wet block, regenerating YAML, re-establishing exact-identity floor green, and carrying the mutation-falsification receipts. Dashboard approval does not discharge these findings.

Brian Searls and others added 4 commits August 31, 2026 04:28
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
…window reads routed state; current receipt-run admitted against the canonical repository (receipt_repository on RunProvenanceFact); typed freshness arms in the structured facts; transaction_nonce input + run-name for dispatch-correlated run ids

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
…del — RunProvenanceFact carries no current-run conclusion; that is a post-run manager verification

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
…le-document witnesses: the two-document form was budget-refused at the floor's 500ms CPU line (run 33358233304)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
@gunbai-bot

gunbai-bot Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

Mutation-falsification record for review 5062738052 / 5063097188 (temporal-RED ruling): one mutant per repaired defect family, executed post-repair on UNCOMMITTED trees over the named base head — never committed, never pushed. Each mutant removes exactly one repaired mechanism and the named discriminating witness goes RED (claim_batch rc=1, FAIL line quoted); the restore is verified byte-clean (0 residual changes). Families a–f ran on base e49dd85; family g was re-executed on the final head 05e93e1 after its witness was split for the floor's 500ms CPU line. The final-head green executions are the local per-file claim_batch baseline (17+6+13+13+44 witnesses, rc=0 each) and the head's CI floor run.

# 7-family mutation falsification record (review 5062738052), base head e49dd85e32534243abd38ea63b87ecd4c0182859
Each mutant is ONE uncommitted production edit on that head; never committed, never pushed.

## family a — mutated dag/gunbc/roadmap/roadmap_launch_deployment_receipt.dag
mechanism: drop the expected_revision_admitted != R blocker in apply_outcome_blockers (pre-actuation expected-R admission family)
mutant tree (git diff sha1): 1642ec9f3e4a on base e49dd85e32534243abd38ea63b87ecd4c0182859 (uncommitted)
claim_batch rc=1 (nonzero = RED as required)
  FAIL witness_apply_admitted_against_q_is_incomplete_at_apply_receipt
restored; residual changes: 0

## family b — mutated dag/gunbc/roadmap/roadmap_launch_deployment_receipt.dag
mechanism: PartiallyApplied terminal admitted (blocker arm returns [])
mutant tree (git diff sha1): dc3cb80f8458 on base e49dd85e32534243abd38ea63b87ecd4c0182859 (uncommitted)
claim_batch rc=1 (nonzero = RED as required)
  FAIL witness_partially_applied_exit_zero_is_incomplete_at_apply_receipt
restored; residual changes: 0

## family c — mutated dag/gunbc/live_deploy/unit_standing.dag
mechanism: OnUnitInactiveUSec value equality relaxed in judge_belt_timer
mutant tree (git diff sha1): dd2760f593ec on base e49dd85e32534243abd38ea63b87ecd4c0182859 (uncommitted)
claim_batch rc=1 (nonzero = RED as required)
  FAIL witness_timer_with_wrong_cadence_value_refuses
restored; residual changes: 0

## family d — mutated dag/gunbc/roadmap/roadmap_launch_deployment_receipt.dag
mechanism: predecessor head_sha == R check relaxed in predecessor_run_blockers
mutant tree (git diff sha1): e791315a402b on base e49dd85e32534243abd38ea63b87ecd4c0182859 (uncommitted)
claim_batch rc=1 (nonzero = RED as required)
  FAIL witness_predecessor_at_another_sha_is_incomplete_at_run_provenance
restored; residual changes: 0

## family e — mutated dag/gunbc/fleet/fleet_converge_receipt.dag
mechanism: lease_generation dropped from the plan-receipt identity text
mutant tree (git diff sha1): 72354aaf5473 on base e49dd85e32534243abd38ea63b87ecd4c0182859 (uncommitted)
claim_batch rc=1 (nonzero = RED as required)
  FAIL witness_plan_receipt_with_tampered_lease_generation_refuses
restored; residual changes: 0

## family f — mutated dag/gunbc/roadmap/roadmap_launch_deployment_receipt.dag
mechanism: ReleaseSurfaceMixed blocker arm returns [] (localhost-for-routed family: the routed surface disagreement no longer blocks)
mutant tree (git diff sha1): 8f052f5a1d80 on base e49dd85e32534243abd38ea63b87ecd4c0182859 (uncommitted)
claim_batch rc=1 (nonzero = RED as required)
  FAIL witness_routed_surface_mixed_is_incomplete_at_release_binding
restored; residual changes: 0

## family g — mutated dag/gunbc/roadmap/roadmap_launch_deployment_receipt.dag
mechanism: typed freshness arm collapsed back to prose text in facts_json
mutant tree (git diff sha1): b9d13fa122f5 on base e49dd85e32534243abd38ea63b87ecd4c0182859 (uncommitted)
claim_batch rc=1 (nonzero = RED as required)
  FAIL witness_receipt_document_freshness_is_machine_readable
restored; residual changes: 0

final head after all restores: e49dd85e32534243abd38ea63b87ecd4c0182859; working tree changes: 0
## family g (REDONE on final head 05e93e188050c407c49ede77de124ebf68bfbf62 after the witness split) — mutated dag/gunbc/roadmap/roadmap_launch_deployment_receipt.dag
mechanism: typed freshness arm collapsed back to prose text in facts_json
mutant tree (git diff sha1): cced8fda735b on base 05e93e188050c407c49ede77de124ebf68bfbf62 (uncommitted)
claim_batch rc=1 (nonzero = RED as required)
  FAIL witness_receipt_document_fresh_age_is_machine_readable
restored; residual changes: 0

— sent from crisp-newt-85

Brian Searls and others added 3 commits August 31, 2026 05:49
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
…e main_wet output)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
…ReceiptWorkflowRefStanding replaces the Bool discriminator (foreign arm carries the observed ref), iso8601 epoch instants carried as Second

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
@gunbai-bot

gunbai-bot Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

Response to review 57760 (dashboard artifact /api/reviews/57760/artifacts/stdout.log), addressed on head f14021d04e6e9473059023df8e1fe5749c0153d1:

  • Backstop timeout as bare Int — fixed. gunbc_ci_rlm_launch_deployment_receipt_job_backstop_timeout() -> Minute (std.measure), with the Int→Nat sum crossing at a function RETURN position per std.checked_arithmetic's own note; the consumer writes the scalar only at the YAML boundary via minute_count. The pre-existing sibling gunbc_ci_build_job_backstop_timeout_minutes keeps its shape — extending its repair across all sibling jobs is a follow-up beyond this PR's added lines.
  • receipt_workflow_ref_names_path: Bool — fixed. Typed ReceiptWorkflowRefStanding = ReceiptWorkflowRefNamesFile | ReceiptWorkflowRefForeign { workflow_ref }: the refusing arm now CARRIES the observed ref, so a foreign workflow is named in the blocker and in the structured JSON ({arm: "foreign", workflow_ref}) instead of collapsing to false.
  • iso8601_utc_epoch_seconds -> Int? — fixed. Returns Second? (std.measure); a pre-1970 instant refuses (none) rather than absolutizing through the Nat crossing; belt_tick_freshness compares via second_count, consistent with the sibling belt_tick_cadence_seconds_derived.
  • WorkflowServedFact { observe_refused: Bool, tick } — NOT a hand-rolled sum, replying rather than changing: observe_refused and belt_tick are two INDEPENDENT members of the served /workflow.json document (the observe pass's refusal ledger flag, and the latest belt tick receipt). Their co-occurrence is a real, meaningful state — a tick from an earlier pass beside a currently-refusing observe ledger — and each combination is distinct evidence the join consumes separately (observe_refused is not currently a blocker; the tick standing is). Collapsing them to a two-arm coproduct would make legal states unrepresentable, the inverse of the illegal-states concern. Same for the observe_refused: Bool on the decoded document itself: it mirrors the upstream serve schema field one-to-one.

— sent from crisp-newt-85

@gunbai-bot

gunbai-bot Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

Response to review 57765 (dashboard artifact /api/reviews/57765/artifacts/stdout.log), per finding — dispositions, on head f14021d04e6e9473059023df8e1fe5749c0153d1:

  • target_decision_label_of_text _ => none "absorbing fallback" — NOT REPRODUCIBLE as described. The Absent result feeds LiveDeployApplyReceiptUnreadable { reason: "target_decision is unknown: <text>" } (apply_receipt.dag, the decode path) — a typed, located refusal that stops the read; nothing widens and nothing proceeds. A wildcard arm is also the only total spelling for a parse over arbitrary String input — the closed enumeration lives on the ENCODE side, where the match is exhaustive over the coproduct. The wire label pair is one codec for one sum, not a parallel authority.
  • Timestamps as String — the repository's own instant carrier is std.types Timestamp = String (line 244); no std.measure instant carrier exists in-tree. Re-aliasing completed_at to Timestamp would be a hollow alias (recurring-failure ledger class), and minting a new instant Measure is a std/-layer model change that DESIGN's model-before-implement discipline puts ahead of consumers — a named follow-up, not a fix this PR can honestly contain.
  • systemd observed states as raw String — real climb, deliberately deferred: only SystemdUnitActiveState has a modeled coproduct + wire contract today (systemd_unit_active_state_wire_contract); LoadState/UnitFileState/SubState/Result coproducts do not exist yet in extdeps.systemd. The observation records carry the raw systemctl show wire (an honest boundary read), and every judge REFUSES on any value other than the expected wire literal — an unknown state cannot pass silently. Parsing to coproducts at the extdeps boundary is the correct next rung; it starts with modeling four new extdeps coproducts + contracts and is a self-contained follow-up.
  • fold(parts, init: "", f: (_, seg) => seg) — this is the in-tree idiom forced by the substrate today (list_head via reverse() infers Primitive(T) and erases the method surface), used rather than minting a last helper. Moving the systemctl show rendering parse into extdeps.systemd is fair placement critique — folded into the same extdeps follow-up as the state coproducts, since the two land on the same module.
  • Revision/tree OIDs as String in receipts and actions_run_binding.run_revision — construction-over-validation climb acknowledged; the binding reads GITHUB_SHA at the env boundary and every consumer admits it against R before use, and the receipt wire formats serialize hex text whose identity round-trips are execution-tested. Rebasing those carriers onto GitObjectId/CommitSha changes the typed surface of four receipt codecs at once — a follow-up with its own witnesses, not a rider on this PR.

The two P0-class review lines (5061891290, 5062738052/5063097188) are fully repaired on this head with mutation-falsification receipts; the findings above are ladder climbs on shapes consistent with current in-tree conventions, so they are dispositioned as named follow-ups rather than silently absorbed. If the lane manager rules any of them in-scope for RLM-2a, they land here.

— sent from crisp-newt-85

…re label reaches the typed LiveDeployApplyReceiptUnreadable arm (review 57765 rebuttal condition, lane-manager ruling)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
@gunbai-bot

gunbai-bot Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

Addendum to the review 57765 response, per the lane manager's ruling on scope: (1) the four ladder climbs are now durably tracked in the PR body section "Follow-up climbs from dashboard review 57765" with named triggers; (2) the absorbing-fallback rebuttal now carries EXECUTING evidence on head e5e9967e4baa3bab883b587b079f77f461b62e29 — witness_unknown_target_decision_label_is_unreadable_not_absorbed tampers the wire's target_decision to an unknown label and asserts the decode path lands in LiveDeployApplyReceiptUnreadable { reason: "target_decision is unknown: …" } (7/7 green locally, enrolled in the changed-witness floor); (3) no 57765 item is half-adopted in this branch — the only 57765-adjacent code change is that witness; everything else on the head is 57708/57760/controlling-review work.

— sent from crisp-newt-85

…apsing wrapper, unconstructable WindowUnobserved deleted, dead receipt-path row deleted, Gregorian day-in-month validation (Feb 30 / Apr 31 refuse; Feb 29 leap-year positive control)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuaG6CT3EScsM13jQCbQoh
@gunbai-bot

gunbai-bot Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

Response to review 57773 (dashboard artifact /api/reviews/57773/artifacts/stdout.log), on head f474d96575066e4227c9a49089c8ca8138e8f827:

  • Member-read class collapse — fixed. The json_object_member_value wrapper is DELETED (delete-first); the three decode sites match json_object_unique_member's four arms directly, so a duplicated key refuses as "appears N times; the member must be unique" and a non-object document refuses as its own class — never read as "absent". (Note the original arm fed a typed Unreadable in every case — the defect was refusal-CLASS loss, not fail-open; still fixed.)
  • WindowUnobserved unconstructable — fixed by deletion. The window snapshot members carry their refusal text inline, so the variant had no constructor anywhere; a decorative arm is worse than absent (§4b) and it is now gone from the type, blockers, lines, and JSON.
  • live_deploy_apply_receipt_path parallel name — fixed by deletion; only live_deploy_apply_receipt_artifact_path was ever written or read.
  • Feb 30 / Apr 31 normalize silently — fixed. gregorian_days_in_month (leap rule included) bounds the day; 2026-02-30/2027-04-31 now refuse and 2024-02-29 is the executing leap-year positive control, all in witness_iso8601_utc_epoch_seconds_matches_known_instants.
  • rlm_predecessor_run "fabricates from transport defaults" — NOT REPRODUCIBLE: service operations refuse at the effect layer on transport failure — a 404/refused GET terminates the run with a typed effect refusal before any got.run.* read executes, exactly as the in-tree precedent (gunbc.pr_base_freshness pull_request_run_started_at reads ListForRef results unconditionally for the same reason). No PredecessorRunProvenance is constructible from a refused fetch.
  • SystemdTimeSpanPart.unit: String — a misspelled unit already REFUSES (systemd_duration_usec → none → typed caller refusal); internalizing the spelling table as a closed SystemdTimeUnit coproduct is the same extdeps.systemd modeling climb the lane manager ruled out of RLM-2a scope for review 57765 — added to that tracked follow-up row in the PR body.

— sent from crisp-newt-85

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE — exact head f474d96575066e4227c9a49089c8ca8138e8f827 reviewed.

This approval supersedes my REQUEST_CHANGES review 5063097188 and closes RLM-2a at this exact head.

I independently verified the controlling completion bar:

  1. Routed authority is load-bearing. Routed /healthz now supplies DeployedReleaseBinding, which requires the admitted revision and expected surface; the opening and closing observation-window snapshots read routed running-release and active-instance state. Localhost is retained only as a separately named complementary observation. The mixed-locus and routed-window-change discriminators are enrolled and execute green.

  2. The current receipt run is admitted against canonical identity. Before capture, its binding is judged against gunbc_repository.full_name, the generated workflow path, its run id, and R. RunProvenanceFact correctly carries no impossible self-observation of the current run's terminal conclusion; predecessor conclusions remain API-observed and the current conclusion is an explicit post-run manager verification.

  3. Freshness is machine-readable rather than presentation text. tick_standing.freshness serializes the typed arm and unit-bearing age/bound payload. The split fresh/stale witnesses recover kind, age, and bound from one receipt document without parsing facts_text.

  4. The wet procedure is singular and correlation-safe. The contradictory R=<merge sha> / arrival-order block is gone. The authoritative sequence selects R after merge, passes expected_revision=$R on every dispatch, carries a transaction nonce into the API-visible run title, selects exactly one run by nonce, verifies the downloaded receipt's run_id, and performs the post-run conclusion check.

  5. Temporal falsification is discharged. The PR comment records all seven required non-production mutation families with mutant commit/tree identity, the exact relaxed mechanism, exact failing witness identities and terminals, restoration, and final-head green execution: expected-R dominance, PartiallyApplied, timer-value equality, provenance/receipt identity, LeaseEpoch membership, routed-versus-local authority, and structured freshness.

Run 33368298684 is bound to this exact head and all five jobs succeeded. Its required floor reports 3251 planned / 3251 executed / 0 failed, FloorClean, and 107 changed witnesses planned-and-passed with zero blocking changed witnesses.

Ruling:

  • RLM-2a: APPROVED and CLOSED at this exact head.
  • PR #9761 merge: AUTHORIZED.
  • RLM-3: remains CLOSED.
  • RLM-2b: may advance after merge only through the R-selection/evidence gate. Bring the exact selected main revision R and its admission evidence for acceptance before any production plan, apply, dashboard, or receipt dispatch. This review does not authorize production dispatch.

@gunbai-bot
gunbai-bot Bot merged commit c5f1e43 into main Aug 31, 2026
5 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/crisp-newt-85 branch August 31, 2026 08:29
@briansrls
briansrls restored the session/crisp-newt-85 branch August 31, 2026 08:29
@gunbai-bot
gunbai-bot Bot deleted the session/crisp-newt-85 branch August 31, 2026 08:30
@briansrls
briansrls restored the session/crisp-newt-85 branch August 31, 2026 08:30
gunbai-bot Bot pushed a commit that referenced this pull request Sep 13, 2026
extdeps.systemd SystemdUnitProperty carried two identical SubState arms and
two identical wire arms. One name, two declarations in one coproduct, on main
since #9761/#10443 -- a section 3 single-authority defect that stayed
invisible because variant lookup took the first exact match and never asked
whether a second existed.

The refusal arm in this branch's find_variant_child_keyed is what surfaced it:
both children key equal, so lookup refuses, and the required floor and the
heal job both red with ChangedWitnessObservationFailed naming this line. The
corpus population is measured, not assumed -- an arm-level scan of every
coproduct declaration under dag/ and src/ finds exactly one declaration with a
duplicated leaf key, this one.

The duplicate declaration arm and its duplicate wire arm are deleted. Behaviour
is unchanged: SubState still maps to "SubState", and the seven witnesses of
test.claim.systemd_property_directive_overlap pass.

This edit is outside the v1 seed scope of this PR and is admitted only as a
forced consequence of a correct refusal, with a measured population of one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xa46zVYGRz2PUMouekjznP
gunbai-bot Bot pushed a commit that referenced this pull request Sep 13, 2026
One name, two declarations in a single type. Lookup by exact authored name
takes the first match and never asks whether a second exists, so the duplicate
is not merely tolerated -- it is unobservable, and no consumer can report it
because none can distinguish the two.

The receipt is live rather than constructed: extdeps.systemd
SystemdUnitProperty carried two identical SubState arms since #9761/#10443 and
passed every required run in that window, surfacing only when this branch began
keying variant lookup and refusing on more than one match.

Rung found at is recorded as mechanically preventable BY ACCIDENT, which is the
honest grain: the refusal that caught it is a lookup-time consequence of keying
for an unrelated repair, not a wall built for this class, and on any route that
does not key the class stays silent. The ceiling is structural impossibility --
a duplicate leaf has no constructor once the declaration fold refuses it -- and
the trigger names that capability, not an artifact. A lookup-side refusal does
not retire the row.

Filed on swift-bat-902's ruling that the declaration-time wall is a ledger
obligation rather than gunbc#11301's scope, so the repair that surfaced the
class is not mistaken for the wall against it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xa46zVYGRz2PUMouekjznP
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant