Skip to content

Prereq-drift ruling: restore 5-collapse-v1's dropped prereqs as GateDeletion bricks - #7110

Merged
briansrls merged 79 commits into
mainfrom
session/sharp-bee-290-roadmap-converge
Jul 23, 2026
Merged

briansrls merged 79 commits into
mainfrom
session/sharp-bee-290-roadmap-converge

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Records the deliberate ruling on the PREREQ-DRIFT flag from PR #7104 (roadmap row 5-collapse-v1, superseded by this plan): the old terminal-collapse bar required HAND-queue drain + real fixed point + test-migration + seed-honesty; the three-gate remodel carried forward only the fixed point (deliberately re-based byte → behavioral). The other three were not deliberately dropped — this PR rules and records instead of leaving the narrowing silent.

The ruling (prereq_drift_ruling_2026_07_23 note row): the scope splits. The three gates are the interpreter-deletion bar and correctly name none of the three. The terminal claims do require them, so they return as GateDeletion bricks:

  • hand_queue_drain — before v1_quarantine: quarantine claims products-still-build, but the gunbc CLI (cli_run.rs, ~12.1k LOC) is itself a HAND_MAINTAINED src/v1 file — the claim is unwritable undrained. Carries the receipt history (24→7 drained, main.rs flip-back self-revert Flip main.rs from HAND_MAINTAINED to GENERATED post-#6053 #6226, kernel-D blocked on emit_host transport = the live Lane C dependency).
  • test_migration — before v1_delete: the delete-guard wall already blocks by construction; the brick adds the executed coverage receipt against the frozen 881-fn / 28,054-LOC baseline so deletion fires on a counted green, not on guard silence.
  • seed_honesty_decision — before v1_delete, a DecisionGate: operator rules whether DDC gates deletion. Either way the modeled SeedHonestyDischarge witness is fail-open by construction (evidence arg = checked atom, Holds trivially) — flagged as a standing §5 defect whose red-case fix is NOT gated on the decision.

Test plan

  • gunbc compile over the roadmap_page.dag consumer closure: 99 errors with and without this edit (pre-existing soft-class over-report on scoped local compiles; control run receipt in-session) — zero delta from this change
  • No committed generated artifact projects this file (roadmap page is served live; not in generated_artifact_gate.dag)
  • CI floor on this PR

🤖 Generated with Claude Code

Brian Searls and others added 30 commits July 20, 2026 14:39
…t-closure root fix

Delta-first refresh of the v1-deletion plan authority against this session's landings:
- witness_family_fanout -> DONE (all 9 families green + trustworthy controls: #6912/#6917/#6918)
- new milestone emit_import_closure_root: the multi-layer emit-import peel root-caused into
  ONE transitive-closure derivation (operator ruling 2026-07-20); FreeMonoid was one layer, not the gate
- probe_flip_fanout + deep_module_lanes -> both GATED on emit_import_closure_root (flip wave is
  NOT orthogonal; it shares the import-closure root and fans out in parallel with deep lanes on cargo-green)
- unresolved_error_diagnosis -> diagnosis DONE, partial fix landed #6906 (mid-peel)
- ci_floor_cutover -> ledger overlap-started #6915 with a §3 hand-declared-disposition defect to root-cause
- rulings recorded: root-cause not face-by-face; cargo-green + witness-green always (no mid-peel merges)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…p; artifact is its projection

Operator: "your job is to get us to a full and confident plan — we can antagonize
it — make this a roadmap and the artifact a projection of it." The plan authority
now models the three-gate v1-delete bar directly (§3 single authority; the
selfhost-dashboard.html artifact projects it, delta-first):

- PlanGate enum groups every milestone under Gate 1 (emitter fixed point),
  Gate 2 (honest frontier), Gate 3 (ledger green), or GateDeletion.
- BrickState (Placed|InFlight|Gated) per milestone.
- ConfidenceBasis{basis, risk, antagonize} per milestone — the attack surface
  that makes the plan antagonizable item by item (the confidence-probe lane
  fills in risk/antagonize).
- PlanGateSpec rows carry each gate's name + what it proves.
- 23 bricks (was 13): adds generic_t_rendering, the Gate-2 property bricks
  (typed_frontier/frontier_dispositioned/no_frontier_lies), the Gate-3 ledger
  bricks (ledger_modeled/ledger_projection + the 3 spine receipts), and
  emit_representation_mismatch — the E0308 layer (~4400/deep module) the
  confidence-probe just exposed once generic-T cleared (quiet-bee #6924
  residual histogram). Rewired the Gate-1 chain so E0308 sits between the two
  known roots and the deep-module lanes.

NOT "27/27 modules flipped" — the doc string states the bar is emitter fixed
point + honest frontier + ledger green; some modules stay SeedRetained by
necessity.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tion

The cycle-5 remodel put literal braces in prose strings (SeedRetained{reason,
migration_trigger}). In the seed grammar `{...}` inside a string is
interpolation (render.dag escapes them as \{ \}; the seed has ExprStringInterp),
so `{reason, migration_trigger}` parsed as an interpolation expression and blew
the top-level item parser: "expected item declaration". The known-good cycle-4
file had zero in-string braces.

Fix: replaced the 3 occurrences with parens — SeedRetained(reason,
migration_trigger). Verified by execution with a discriminating control:
v1_src_dag_parse reds the pre-fix version with the exact CI error and greens
the fix.

Also folds quiet-bee's E0308 type-pair sizing into emit_representation_mismatch:
206 pairs but TOP 5 = 82% (Symbol/String ~2100 = one std fork, FreeMonoid/String
~1038, Vector/FreeMonoid ~150, Optional/Option ~150) — the layer is TRACTABLE
(3-4 construction walls at the authority, not 206 one-offs), so Gate-1 depth is
now bounded. Risk downgraded from "could dominate Gate 1" accordingly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…244)

cursor/composer-2.5 REQUEST_CHANGES caught a real §3 gap: the prose
(ci_floor_cutover lane_state + critical_path_note) says the cutover is gated on
the ledger receipts, but no PlanDependency wired ledger_projection / the 3 spine
receipts into ci_floor_cutover — they pointed only at v1_delete. So the modeled
DAG allowed CI cutover (and transitively quarantine) before Gate 3 completed.

Fix: retarget the 4 Gate-3 receipt edges from v1_delete to ci_floor_cutover, so
Gate 3 -> ci_floor_cutover -> v1_quarantine -> v1_delete. Now every Gate-3
receipt transitively gates BOTH quarantine and delete (verified by execution:
reachability holds for all 4), with no redundant edge (the old direct
receipt->v1_delete edges are subsumed by the chain). Updated v1_quarantine and
v1_delete lane_state prose to state the transitive gating explicitly, so a reader
of the dependency list cannot treat either as reachable without the ledger green.

DAG re-verified acyclic (Kahn over all 23 milestones); parse-checked by execution.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rity pages only) + regen golden

Render the v1-delete three-gate progress (Gate 1 emitter fixed point ·
Gate 2 honest frontier · Gate 3 ledger green) driven from
gunbc.v1_deletion_plan on the live srv1 roadmap dashboard `/` and
`/roadmap` pages — a single authority, no data duplication.

Fixes two CI-red witnesses from the first cut:
- roadmap_page_keystone_holds: the three-gate section had been spliced
  into the GENERIC roadmap_page(doc, merged) renderer, so it injected
  into every doc incl. the empty test doc, breaking the
  "empty doc -> empty <main>" invariant. Three-gate progress is
  AUTHORITY content (renders v1_deletion_plan), so route it through
  the _for_authority variants via a private _impl + main_prefix param
  (authority output byte-identical). Add
  witness_authority_shows_three_gate_progress as the positive
  coverage assertion (authority page HAS it; empty page is the
  discriminating RED control).
- live_deploy_emit_holds / witness_apply_script_matches_committed_golden:
  regenerate .github/live-deploy-srv1-apply.sh so the embedded server.js
  dashboard pages carry the three-gate content.

Proven green by execution: roadmap_page_keystone_holds PASS,
live_deploy_emit_holds PASS.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rogress + regen golden

Belt A (#6942) landed the roadmap launch button + /dispatch client
script on the same three dashboard files this branch touches. Combined
both in roadmap_page.dag: the _impl/main_prefix three-gate feeds
#6942's conditional dispatch_client_script() body path (empty doc still
yields a bare <main> with no script). The witness file auto-merged into
one roadmap_page_keystone_holds carrying both feature families.
Regenerated .github/live-deploy-srv1-apply.sh from the merged sources so
it carries three-gate progress AND the dispatch button (the auto-WIP
checkpoint had committed the in-progress merge with conflict markers).

Proven green by execution on the merged tree: roadmap_page_keystone_holds
PASS (three-gate + dispatch + all prior conjuncts), live_deploy_emit_holds
PASS (golden matches).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gates

cursor/composer-2.5 (REQUEST_CHANGES) correctly flagged that
three_gate_progress_markup() mapped all of v1_deletion_gates including
GateDeletion, rendering 4 rows under the "three gates" heading.
GateDeletion is downstream cutover/delete ("proves nothing on its own"
per the authority), not one of the three proving gates.

Filter to the proving gates via tg_is_bar_gate (GateDeletion => false);
the heading is now literally true. Witness asserts Gate 1/Gate 3 render
and "Cutover and delete" (GateDeletion's name) does NOT. Regenerated the
apply-script golden (cutover_rows=0). roadmap_page_keystone_holds PASS.

Finding 1 (exclude the non-bar-brick probe_flip_fanout from Gate 2's
count) needs a typed discriminator on PlanMilestone in the plan
authority — landing separately pending authority-edit confirmation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…hrink from gate counts

cursor/composer-2.5 correctly flagged that the gate progress counted
probe_flip_fanout in Gate 2's denominator even though the authority
declares the flip wave "not itself a bar-brick" (seed-shrink beyond the
fixed-point minimum) — so Gate 2 could never read 100%.

Fix (operator-cleared to edit the authority in this PR): add a typed
BrickRole = BarBrick | SeedShrink discriminator on PlanMilestone
(v1_deletion_plan.dag); probe_flip_fanout is the one SeedShrink, the
other 22 are BarBrick. The projection's tg_gate_bricks now filters to
bar-bricks, so tg_gate_total / tg_gate_placed / the remaining list all
exclude seed-shrink. Gate 2 reads 3/4, not 3/5.

Witness asserts the seed-shrink brick's title ("std_dup-gated modules")
does NOT render in the three-gate section (discriminating: removing the
filter reds it). Regenerated golden (seedshrink_leak=0).
roadmap_page_keystone_holds PASS, live_deploy_emit_holds PASS by
execution. Merged main (#6922 plan authority now landed).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ration

declared_gap_steps_carry_interim_realization_authority required every
DeclaredGap's interim_realization to cite `ctrl:` OR (`extdeps.` AND
`gunbc.`). #6947 (Wave C3, merged to main) correctly migrated the
os-install-actuated gap's nbd_proxy realization from the extdeps shell
transport (`extdeps.bmc.webui.nbd_proxy_serve ShellProgram`) to a gunbc
typed host-effect (`gunbc.host_effect_nbd_proxy_serve`), a more-grounded
authority that no longer routes through an extdeps dep. The now-purely-
gunbc realization made the `(extdeps. AND gunbc.)` conjunction fail, so
the fold returned Bool(false) — a main-inherited CI red (owner session
crisp-bat-221 archived; no fix in flight).

Relax the over-specific conjunction to the invariant's actual intent: a
DeclaredGap must cite >=1 grounded authority — `ctrl:` OR `extdeps.` OR
`gunbc.`. Fail-closed property preserved: a gap citing NONE still reds;
ModeledCompose arm unchanged. RED proven by CI execution on 3644226
(returned Bool(false)); this greens it.

Also restores dag/test/fixture/m4_universal_governed_corpus.dag to
origin/main (a phantom auto-WIP edit had crept in during local repro).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Brian Searls and others added 18 commits July 22, 2026 14:04
…D, type-ref-import-missing is the successor class on 5 modules (3 unique symbols); 05_eval + 06_translate knowledge_attributed -> execution_measured; emit-shape + struct-literal-body classes named; materialization_carriers advanced off import-closure. Receipts in TSV + honest_frontier_refresh_2026_07_22_post_merge_note

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ted -> execution_measured (TSV row 05_emit E0433 UriScheme landed by the resumed background sweep after the 13-row read) — roster and receipt back to one authority

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ts purpose: sweep-order ranks verified against frontier authority)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…7-22 execution receipts

The plan-milestone rows lagged the frontier/probe carriers (the staleness the
operator saw on the freshly deployed srv1 roadmap). Re-based on receipts, both
directions — two flips forward, one flip BACK:

- generic_t_rendering InFlight -> Placed: class extinct by execution (#7033 +
  21-module re-sweep, zero curated_cargo_probe_generic_type_render rows); Phase-2
  typed-REFUSE residue named as non-bar hardening.
- trigger_renegotiation InFlight -> Placed: the mechanical frontier-row update
  landed (#7040 trigger refutation + #7058 refresh); no namespace-gated trigger
  remains on the frontier.
- std_dup_assembly_fix Placed -> InFlight (honest-green rule): E0255 resurfaced
  post type-surface regen as first-error on the curated 4-module baseline —
  suspected different root (emitter-synthesized std use-lines, #7068 pub-use
  family). Now the single first-error blocker for the cargo-green fan-out.
- emit_import_closure_root: type-surface arm landed (#7057), E0422/E0433 class
  cleared by execution; representative cargo-green bar still unmet behind E0255.
- emit_representation_mismatch: the ~4400-sized layer measured GONE on 04_infer
  (e0308_all=0); gate premise re-pointed to std_dup + post-clear re-histogram.
- deep_module_lanes: gate premise re-based accordingly.

Verified by execution: plan closure compiles 0 diagnostics; roadmap_page,
roadmap_frontier, roadmap_register witnesses all true; generated_artifact_gate
main_wet ExitSuccess with zero drift.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…migration, seed-honesty as GateDeletion bricks

The superseded roadmap row 5-collapse-v1 required four prereqs; the
cycle-5 three-gate remodel carried forward only the fixed point. Ruling
(operator-delegated via the PR #7104 PREREQ-DRIFT flag): the three gates
are the interpreter-deletion bar and correctly omit them; the terminal
claims (v1_quarantine products-still-build, v1_delete) do require them.
hand_queue_drain lands before quarantine (the gunbc CLI is a HAND src/v1
file — products-still-build is unwritable undrained), test_migration and
seed_honesty_decision before delete. The seed-honesty witness fail-open
defect is flagged as owed regardless of the decision outcome.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@briansrls
briansrls merged commit d70ccac into main Jul 23, 2026
3 checks passed
@briansrls
briansrls deleted the session/sharp-bee-290-roadmap-converge branch July 23, 2026 17:40
briansrls added a commit that referenced this pull request Jul 23, 2026
Kept branch current with main's witness/census churn; regenerated the eligibility
census TSV+histogram so committed == emit(merged roster) (876 entries, emit's
internal roster==count check green). Generated-artifact drift clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Jul 23, 2026
…eanup (#7027)

* fix(srv3): DirectLayout on-ISO autoinstall + os-install reconcile spine (T3/T4)

Rebased onto main: StoragePolicyDirectLayout on seeded ISO autoinstall,
split reconcile modules (core/types/receipt/apply/dry_run/record_approval),
honest freeze scope and printf receipt echo, fail-closed observed_at parse,
ServeReady virtual-media session match, and review-driven witness coverage.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(srv3): observe script bash syntax — drop stray HTTP_CODE= before if

Serve receipt echo was concatenated into curl_tail as HTTP_CODE=if test…,
breaking live reconcile observe on srv1. Witness guards the regression.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(srv3): observe script curl HTTP_CODE — remove extra closing paren

$(curl … || echo 000) had a stray ) breaking bash on live srv1 observe.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs(srv4): BMC onboarding gap analysis — srv3-hardcoded plan + gcloud not provisioned

srv4 racked, BMC at FactoryDefault (403 PasswordChangeRequired). The rotation
workflow (bmc_converge_credential_idempotent, wired into host_standup_spine) is
fully modeled and fail-closed, but bottoms out on the srv3-hardcoded
new_altra_onboarding_plan and assumes gcloud is present. Documents 4 gaps
(G1 per-host parameterization [dispositive], G2 gcloud self-provision, G3
operator-token handler, G4 srv4 identity rows) for review before modeling.

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

* feat(srv4): close BMC onboarding gaps — per-host plan, gcloud self-provision, operator-token handler, srv4 identity

Full close of the four gaps from the analysis doc (PR #7027), so BMC onboarding
is hands-off per-host instead of srv3-hardcoded:

G1 — per-host parameterization: altra_onboarding_plan(bmc_host, secret_name)
  constructor + srv3_onboarding_plan / srv4_onboarding_plan rows replace the
  srv3-literal new_altra_onboarding_plan. Threaded `plan` through every
  bmc_onboard func; de-nicknamed srv3_gcp_project -> bmc_secrets_gcp_project
  (fleet-wide). Zero-arg per-host entries srv3_converge_credential /
  srv4_converge_credential are what the standup decl_ref + executor invoke.

G2 — gcloud self-provision: modeled gcloud_cli_tool (extdeps/tools/gcloud.dag)
  + package_google_cloud_cli, and bmc_credential_actuator_toolchain_requirement
  (curl + gcloud) mirroring the OS-install toolchain-ensure.

G3 — token de-fork: gunbc.auth.access_token_source with
  AccessTokenSource = GcloudPrintToken | OperatorSuppliedToken{token} and
  resolve_access_token, so an operator-supplied token is a first-class handler
  (drives rotation with no gcloud on the actuator).

G4 — srv4 identity: operator_host_srv4 + srv4_bmc_endpoint (.195) in
  fleet_intent_network.

Verified: full-corpus typecheck clean (850 modules, 0 errors) + 11 witnesses
green by execution across every touched module, incl. a new discriminating
srv4_plan_targets_195_with_srv4_secret and the updated endpoint-count witness.

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

* fix(bmc): mint OpenBMC-policy-compliant credential (found by live srv3/srv4 rotation)

First live execution of the rotation flow (srv3's was never run green) surfaced
that mint_bmc_credential's base64 octets are rejected by OpenBMC password
validation (PropertyValueFormatError). A firmware-policy divergence also showed:
srv4 (newer OpenBMC) accepts alphanumeric, but srv3 (OpenBMC 2.07.00, pwquality,
MinPasswordLength 9 / MaxPasswordLength 20) requires a 4th character class.

Fix: Urandom.ReadPassword — composition-guaranteed generator (>=1 upper/lower/
digit/special from the shell/JSON/basic-auth-safe set _.@#%-); mint_bmc_credential
mints a 16-char such password (within 9-20, accepted by both firmwares). The
fail-closed read-back gate correctly aborted every base64/alnum attempt before
rotating, so no lockout. Both srv3 (secret bmc-srv3-admin v6) and srv4 (v2) are
now live-rotated off factory 0penBmc; orphaned pre-rotation versions destroyed.

Full-corpus typecheck clean (850 modules, 0 errors) + witnesses green.

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

* feat(access): model fleet SSH access — operator + automation public keys (durable in repo)

SSH-who, the third principal facet alongside POSIX-who (fleet_posix_accounts)
and GCP-who (fleet_operator_gcp_iam_member):

- extdeps/access/ssh.dag: SshPublicKey type + authorized_keys line renderer.
- gunbc/fleet_ssh_access.dag: operator MacBook key (global break-glass, logs in
  as briansrls) + fleet-automation key (machine access). Both PUBLIC keys grounded
  in the repo (public keys aren't secret). fleet_authorized_keys = both, applied
  to every host by breadth.
- fleet_automation_ssh_privkey_secret → SecretRef to Secret Manager
  'fleet-automation-ssh-key' (project gunbai-secrets, v1). The private key's only
  copy lives there; generated 2026-07-21, local copy shredded.
- keys/fleet-ssh-public-keys.txt: plain-text backup of both public keys.

FOLLOW-UP: fleet-automation-ssh-key has no secret-level IAM binding yet (project-
scoped access). Lock to a dedicated automation SA with secretAccessor, mirroring
bmc-assimilator on bmc-srv*-admin.

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

* fix(bmc): remove fabricated-fallback in onboarding_secret_id (§5 fail-closed)

onboarding_secret_id matched plan.rotated_credential and, on the Chained arm,
fabricated a secret id (plan.bmc.host; pre-existing code fabricated a literal) —
a §5 "fabricated plausible output" fallback. Construction-first fix: narrow the
plan field from rotated_credential: CredentialFlow to secret_name: NonEmptyStr,
so the Chained state is unwritable and the function is total (plan.secret_name,
no match, no fallback). Dropped now-unused std.credentials imports.

Verified by execution: srv3/srv4 plan witnesses (now assert secret_name directly)
+ bmc_onboard load, all green. rotated_credential/Chained gone from the corpus.

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

* feat(access): dedicated fleet-automation SA scoped to the SSH private key

Created service account fleet-automation@gunbai-secrets (least-privilege:
secretAccessor on fleet-automation-ssh-key only, mirroring bmc-assimilator's
scoping). Grounded in the model: fleet_automation_sa_email + SecretOwner record
tying the SA to the private-key secret, so "who owns the private key" is answered
in the repo, not just in GCP. Binding applied out-of-band (provenance recorded);
full WIF SecretAccessGrant modeling is follow-up.

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

* feat(access): bake fleet SSH keys into autoinstall, disable password SSH

Wire the access model into the OS install: UbuntuAutoinstallPayload gains
ssh_authorized_keys (List<SshPublicKey>) + ssh_password_auth; os_install_emit
renders the subiquity ssh section with authorized-keys (operator + automation
public keys) and allow-pw. srv3 payloads set fleet_authorized_keys + allow-pw
false — installed hosts trust the fleet keys and refuse password SSH.

Verified by execution: srv3_os_install_emit witnesses green, incl. a new
discriminating one asserting both key lines present + "allow-pw: false".

Note: identity.password still carries the bootstrap hash; per-host strong
console break-glass credential is part of Step B (per-host install identity).

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

* feat(srv4): autoinstall payload + seeded-ISO rows (Step B)

srv4 host identity baked at install time: srv4_autoinstall_identity (hostname
srv4, console break-glass hash; plaintext in Secret Manager host-srv4-console)
+ srv4_ubuntu_autoinstall_on_iso (NoCloudLocal, DirectLayout, fleet SSH keys,
allow-pw false). srv4 seeded-media artifact rows + srv4_seeded_install_media_remaster
mirror srv3, driven by the same install_media_remaster_script builder.

Dry-run verified (typechecks, script generates, ExitSuccess).

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

* feat(uefi): model UEFI Shell + boot-config solver (dissolve manual UEFI GUI step)

The manual "enter UEFI setup, enable PXE / set boot" GUI step becomes a grounded,
solvable model:
- extdeps/firmware/uefi_shell.dag: UEFI Shell command surface (bcfg boot
  dump/add/mv/rm, map, reset) cited to the UEFI Shell 2.2 spec, with a renderer
  to the real command text + a script folder.
- gunbc/uefi_boot_config.dag: DesiredBootSource (install media | PXE entry) ->
  bcfg command sequence — the UEFI-shell realization of the same "what to boot"
  intent the Redfish BootSourceOverride path already models (§2, one intent / two
  realizations). srv4_uefi_install_boot targets fs0:\EFI\BOOT\BOOTAA64.EFI.

Verified by execution: witnesses assert the exact bcfg sequence for install-media
boot and for PXE-entry reorder.

Next: SOL send transport (extend serial_console, currently capture-only) to drive
these over obmc-console into srv4's UEFI shell.

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

* feat(uefi/sol): SOL send transport + drive UEFI-shell boot-config over IPMI SOL

Confirmed live first (operator's caution): the ASRock ALTRAD8UD OpenBMC 2.07.00
supports IPMI SOL (ipmitool -I lanplus sol info → Enabled, ADMINISTRATOR, port
623). That capability was unmodeled — grounded it now: BmcCapability gains
CapabilitySerialConsole, added to the 2.07.00 list with a live-probe provenance row.

Transport: extdeps.bmc.serial_console gains SolConsoleTransport::IpmiSol +
SolConsoleSendIntent + sol_console_send_script (ipmitool sol activate with piped
input via IPMI_PASSWORD -E; obmc-console send arm too; RedfishSerialInterface send
fail-closed as read-only).

Runner: gunbc.uefi_shell_over_sol turns the solved bcfg sequence into serial input
(\r-submitted) and a SOL send script; srv4_uefi_boot_config_sol_send_intent targets
.195. So the manual UEFI GUI step is now: solve DesiredBootSource → bcfg → drive
over SOL, fully executable.

Verified by execution: witnesses assert the srv4 send carries the bcfg sequence,
the script uses ipmitool sol activate, and the ASRock 2.07.00 row declares the
serial-console capability.

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

* fix(sol): IpmiSol exhaustiveness in srv3_sol_console_capture witness

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

* feat(uefi): model the UEFI Shell command surface + observable environment

Back up and ground the real shell interaction (not ad-hoc poking):
- Command surface expanded: connect -r (ConnectRecursive), devices (ListDevices),
  ifconfig (list / set dhcp / set static) alongside bcfg/map/reset — the commands
  actually used driving srv4 over SOL, cited to the UEFI Shell 2.2 spec.
- Observable environment types: UefiNetworkInterface (+ UefiMediaState), UefiBootOption,
  UefiDeviceMapping, UefiShellEnvironment — so the interaction is observe->decide->act.
- gunbc.srv4_uefi_observed: srv4's ACTUAL environment captured live over SOL 2026-07-21
  (map -r, bcfg boot dump -v, ifconfig -l): NVMe with Windows Boot Manager + EFI Shell,
  eth0/eth2 media present (eth0 link-local 169.254.0.18), eth1/eth3 disconnected.

Finding that motivated this: UEFI network stack is ALREADY up in srv4's shell (eth0 has
media) — PXE-enable via GUI is unnecessary; ifconfig -s eth0 dhcp reaches the network
directly. Windows-on-disk confirmed (operator OK'd wipe).

Verified by execution: new commands render, srv4 observed env asserts eth0-has-link +
Windows-present.

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

* feat(uefi): boot-install decision/diagnostic model (observe→diagnose→decide→act)

Generalize the "we're at a UEFI shell, now what?" case into a goal-directed
decision procedure over the observed environment:

- DesiredOutcome = InstalledFleetNode (the goal: wipe + unattended Ubuntu).
- diagnose_boot_install(env) -> BootInstallSituation: pure read of the observed
  UefiShellEnvironment → InstallMediaReady | NetworkReady | NetworkUpNeedsDhcp |
  NoBootSourceAvailable. Fail-closed: no media + no link says so, never pretends.
- decide_boot_install(situation, goal) -> BootInstallAction: goal-directed; refusal
  is a first-class outcome (RefuseNoSource), not a silent no-op.
- boot_install_commands(action) -> List<UefiShellCommand>?: Absent for a refusal —
  a caller cannot extract a "do nothing" sequence and mistake it for progress.

Grounded on srv4's real observed env: diagnoses NetworkUpNeedsDhcp{eth0} (media up,
link-local) → DhcpThenNetworkBoot → ifconfig -s eth0 dhcp. Discriminating fail-closed
control witness: no-media/no-link env → RefuseNoSource → Absent commands.

Verified by execution.

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

* feat(bmc): model self-contained BMC netboot serve (no runtime central server)

Answering "why srv1?" — it isn't needed at runtime. Model the BMC as the netboot
host: gunbc.bmc_netboot_serve.BmcNetbootServePlan + srv4 instance.
- bmc_netboot_serve_command: busybox httpd -f -p 8080 -h /tmp/netboot (the BMC
  hosts the ~88MB bootstrap: kernel/initrd/grub + a staged static busybox).
- bmc_netboot_grub_cfg: boots /vmlinuz + /initrd with url= at the Ubuntu MIRROR
  (host streams the ~1.5GB bulk directly, never on the BMC) and ds=nocloud-net;s=
  at the BMC's own seed dir.
- bmc_netboot_nocloud_user_data: the served seed = autoinstall_user_data(srv4
  payload) — carries fleet SSH keys + allow-pw:false, same emit as the on-ISO path.

So provisioning is BMC + internet: no central serve host at runtime; srv1's only
role is one-time (cacheable) extraction of the 88MB bootstrap from the ISO.
Scaffold-marked (medium-as-string ssh/httpd glue) like nbd_proxy_serve.

Verified by execution: grub.cfg targets mirror-bulk + BMC-seed, serve cmd is
busybox httpd, served seed carries the fleet keys.

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

* refactor(bmc/netboot): model components structurally in extdeps (no concat blobs)

Per operator direction — model each piece appropriately in extdeps first, legibly,
instead of hand-built concat strings:

- extdeps/firmware/kernel_cmdline.dag: KernelCmdlineArg = KernelFlag | KernelKeyValue;
  kernel_cmdline_render via join/map (cited to kernel-parameters.rst).
- extdeps/bootloader/grub.dag: GrubConfig / GrubMenuEntry (structured), grub_config_render
  via join — replaces the string-blob grub cmdline pattern (cited to the GRUB manual).
- extdeps/tools/busybox.dag: busybox CliTool + service busybox.Httpd.Serve with
  structured argv transport (the idiomatic form, like curl.Http).
- extdeps/firmware/uefi_http_boot.dag: UefiHttpBootEntry + provisioning variants
  (cited to UEFI 2.10 HTTP Boot).

gunbc.bmc_netboot_serve recomposed to build a GrubConfig + UefiHttpBootEntry from the
plan (no bespoke concat); grub.cfg, http-boot target, and BMC-served nocloud seed all
derive from structured values. Bulk from the Ubuntu mirror, seed from the BMC.

Verified by execution: grub.cfg renders the full structured cmdline, http-boot entry
targets the BMC url, served seed carries the fleet keys.

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

* feat(bmc/netboot): model BMC ssh transport + structured staging manifest

- extdeps/bmc/ssh.dag: service bmc.Ssh (ExecScript + PutFile) over sshpass -e
  (password via SSHPASS env, never argv) — structured argv, mirrors curl.Http.
- gunbc.bmc_netboot_serve: staging modeled as a structured manifest
  (BmcStagedFile / StagedContentSource = InlineText | LocalArtifact | FetchFromUri):
  busybox+kernel+initrd+grub as LocalArtifact, the rendered grub.cfg + nocloud
  user-data/meta-data as InlineText. Separates WHAT must be on the BMC from HOW
  it gets there.

Verified: manifest stages the rendered grub.cfg (ds=nocloud-net) and the seed
(fleet keys) inline, 7 files.

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

* feat(exec): transport seam — one command, N transports (§3, no forked blobs)

extdeps/exec/command.dag: ShellCommand { argv } + CommandTransport = LocalShell |
SshExec { ssh_target }; command_over_transport wraps a command's argv with the
transport prefix; shell_command_render joins to a string. One operation, chosen
transport — not a per-site command blob.

- busybox: service busybox.Httpd removed in favor of busybox_httpd_command ->
  ShellCommand (single authority for the command shape; runs local OR over BMC-ssh
  via the seam, no dual representation).
- bmc.Ssh: ExecScript removed (superseded by SshExec transport); PutFile kept for
  file transfer.
- bmc_netboot_serve: the serve command is busybox_httpd_command over bmc_transport
  (SshExec root@bmc); local and BMC renderings both derive from it.

Discriminating witness serve_command_one_shape_two_transports: the same command
renders "busybox httpd -p 8080 -h /tmp/netboot" locally and the sshpass-wrapped
form over the BMC transport.

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

* feat(bmc/netboot): orchestration provision func (realize via the seam)

bmc_netboot_provision: sequences the staged manifest + serve — mkdir + serve go
through the extdeps.exec.command seam (bmc_netboot_run_bmc), artifacts via
bmc.Ssh.PutFile, rendered grub.cfg/seed via Filesystem.Write then PutFile.
process_exit_first_failure collects the first failure (no fabricated success).
srv4_bmc_netboot_provision is the zero-arg entry. bmc.Ssh.PutFile gains a
mock_response for hermetic dry-run. Marked realization scaffold.

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

* fix(bmc/netboot): httpd command uses the staged busybox binary (found by live run)

Live provision revealed the serve invoked the BMC's system busybox (no httpd
applet) instead of our staged static busybox. busybox_httpd_command now takes
busybox_bin; bmc_netboot_serve_command_local passes the staged path
(/tmp/netboot/busybox). Witness updated to the staged-path rendering.

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

* feat(bmc/netboot): model the busybox cross-build (reproducible, not manual)

- extdeps/exec/command: shell_command_render now shell-quotes each arg (handles
  args with spaces like EXTRA_CFLAGS="-march=... -mfloat-abi=..."), robustness fix.
- gunbc/command_runner: run_shell_command / run_shell_commands — generic sequential
  runner over the seam with short-circuit (fold-with-effects, verified).
- extdeps/tools/busybox: busybox_source_1_36_1_url; apt package_gcc_arm_linux_gnueabi.
- gunbc/busybox_bmc_build: BusyboxCrossBuildPlan + busybox_build_commands (fetch →
  extract → defconfig → enable static → disable TC → cross-compile armv5te soft-float
  → install artifact) + busybox_bmc_build_run.

Solves the BMC-httpd wall found live: the AST2500 (armv6, no VFP) SIGILLs on prebuilt
busybox httpd; our conservative-flags build runs clean (verified: httpd serves HTTP 200
on the BMC). busybox_bmc_build_run regenerated the artifact from source end-to-end.

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

* fix(bmc/netboot): srv4 boot NIC is eth2 (leases DHCP), not eth0 (found live)

eth0 has media but its UEFI DHCP falls back to link-local; eth2 leases 192.168.1.196
on the LAN segment with the BMC. Plan boot_interface + witness updated.

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

* srv4 fleet subsumption + BMC virtual-media install path + modeling cleanup

Subsume srv4 into the fleet and get it onto GitHub Actions runners, plus the
supporting install-path modeling and several dissolved shell/§3 forks found
along the way.

Fleet membership (srv4):
- srv4_host + samsung_970_evo_500gb_catalog (its actual drive, cited), LAN
  endpoint 192.168.1.196, srv4_offer, deployed_intent_v1_srv4. Placement solver
  now allocates srv4 runner slots (fleet_concurrent_runs 30->40).

Runner deploy (the width-INCREASE gap, now modeled):
- runner_host_deploy.dag: RunnerHostDeploy intent citing the ctrl installer
  (install-actions-runner.sh) as the bound realization handler (§3 cite-upstream,
  not re-coined). Renders the CTRL_RUNNER_* invocation, the App-key SecretRef,
  and the actions-runner@srv4-NN enables. srv4: user briansrls, 5 slots
  (disk-cap note for the 500GB NVMe vs 2TB fleet).

Execution-surface honesty + toolchain provisioning (§5 model-reality gap):
- fleet_intent_execution_surface no longer lies: container_runtime Present{Docker}
  + toolchains [sccache] instead of none/[].
- extdeps/cache/sccache.dag: SccacheBinaryRelease (pinned v0.15.0 + per-arch
  sha256, cited to mozilla/sccache/releases) + install script.
- extdeps/container/docker_ce.dag: DockerCeAptRepo + packages + rootless-docker
  apt prereq install, cited to docs.docker.com.

BMC virtual-media install path (used to install srv4 end-to-end):
- extdeps/storage/nbd.dag, extdeps/linux/usb_gadget.dag (typed ConfigfsOp list,
  not scattered concats), gunbc/bmc_virtual_media.dag: nbd-server -> nbd-client
  -> configfs mass_storage USB gadget. Unified under extdeps/bmc/virtual_media.dag
  VirtualMediaIntent with the existing nbd-proxy-websocat path (§3 fork dissolved).
- extdeps/firmware/uefi_shell.dag + gunbc/bmc_netboot_shell_boot.dag: shell-native
  tftp/execute boot modeling.

Install bugfixes (root-caused live, captured in the model + witnesses):
- grub.dag: quote kernel cmdline args containing ';' (grub command separator) —
  ds=nocloud;s=... was truncated at ';', dropping the seedfrom, so autoinstall
  fell to interactive. grub_cmdline_arg_render + the seeded-media builders quote it.
- ubuntu_seeded_install_media_remaster.dag: xorriso -boot_image any replay (was
  mkisofs, which destroyed the arm64 El Torito/ESP boot structure); instance-id
  derived from hostname (was hardcoded srv3).

All new modeling lands with witnesses (green) and dissolution markers on the
shell-as-string leaves.

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

* plans: fleet subsumption manual-gaps receipt (srv4 hand-steps -> modeling backlog)

Modeled plan doc capturing every step of srv4 install+subsumption that was done
by hand — each a modeling gap. Two families: (A) credential handling (every temp
credential file = a missing MaterializedSecret lifecycle; reach-secrets ADC;
SecretRef liveness after the stale App-key 401) and (B) provisioning (runner SLOT
provisioning = the width-INCREASE gap fleet-converge.sh already names, documented
in full: pinned ActionsRunnerRelease + per-slot dir seed + count reconcile, all
hand-unrolled this time; fleet runner-user; fresh-host prereqs; configfs
virtual-media install actuator + media-detach lifecycle). Each item carries
acceptance tier + RED control; the plan's dissolution trigger retires item-by-item,
fully gone when srv5 subsumes with zero hand-run shell.

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

* WIP: srv4 pr

* WIP: srv4 pr

* WIP: srv4 pr

* WIP: srv4 pr

* WIP: srv4 pr

* WIP: srv4 pr

* WIP: srv4 pr

* review 41721: shell_quote escapes embedded apostrophes (witnessed); IPv4 link-local/removable-media classifiers grounded on extdeps.firmware.uefi_shell rows (prefix test, cited tokens, dissolve-on to parsed device-path); bmc_netboot_provision folds the staging manifest (single authority; hand-unrolled sequence deleted; FetchFromUri refuses typed)

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

* plans: fold srv4 host-convergence OOM receipt into the manual-gaps doc

Section C added: the 2026-07-23 follow-on where srv4 OOM-killed live PR CI.
Sharper framing than the install-time hand-steps — this is an ENROLLMENT
failure: srv4 is not a member of the modeled fleet (fleet_intent declares
srv1/2/3 only), so the converge derivation cannot name it; the runner
installer hand-pointed at srv4 made it a member in GitHub's eyes and a ghost
in the model. Records: (1) model-without-actuator + emit-unprovable
(KnobUnimplemented refusal AND fleet_converge_emit at 104 compile errors, so
converge can neither apply nor emit today) — the displaced-cost pricing for
2-converge-reland; (2) the interim actuation receipt (swap 8->127G, per-slot
MemoryMax/SwapMax inf->16G/32G derived-equal on identical 125GiB RAM, oomd
installed+active, reclaim timer active — each interim, dissolution =
enrollment + converge lane); (3) the three fixes it prices — actuation lane,
SwapDevice modeled axis, and the enrollment wall as construction (installer
refuses on a host absent from fleet_intent). Canonical host-state rows stay on
the operator sheet (1a lane); this doc is the incident receipt.

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

* WIP: srv4 pr

* WIP: srv4 pr

* WIP: srv4 pr

* crypto.hash: single-variant coproduct via leading-pipe form; verify-line rendering re-homed beside the Digest authority

type HashAlgorithm = Sha256 parsed as a type ALIAS to a nonexistent type
(the grammar's single-name RHS form), so no Sha256 variant constructor
existed and the sccache digest witness failed at runtime with 'undefined
variable: Sha256'. The leading-pipe form selects the coproduct parse path
explicitly. digest_shell_verify_line moves into extdeps.crypto.hash so the
match over HashAlgorithm lives beside its authority; sccache.dag consumes it
with the file path as a parameter.

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

* WIP: srv4 pr

* Regenerate DESIGN.md + fleet-converge.sh from .dag authorities (drift gate fix)

CI generated_artifact_drift_gate_passes was red on 05c6a3b from two
latent drifts, both now regenerated from their authorities via main_wet:

- DESIGN.md: the srv4 open-threads bullet was hand-added to the projection
  but not to design_document.dag (its authority). Added as an li() row there;
  DESIGN.md regenerated to match. docs/plans/srv4-bmc-onboarding-gap.md is a
  genuinely new file needing a reference, so the bullet stays — just homed in
  the .dag single authority, not the generated .md.
- .github/fleet-converge.sh: srv4 fleet enrollment updated the
  FleetConvergeArtifact authority; the committed script lacked the
  'gunbc converge --host srv4' line. Regenerated.

Verified: generated_artifact_drift_gate_passes returns true (exit 0).

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

* WIP: srv4 pr

* De-fork BMC scp transport onto the single ssh/scp posture authority (review 41797)

bmc/ssh.dag (new in this PR) re-minted the sshpass -e + StrictHostKeyChecking=no
+ UserKnownHostsFile=/dev/null posture that extdeps.exec.command establishes as
the single authority — a §3 parallel representation in the same PR that adds the
unified transport seam. Fixed by construction, not a second copy:

- command.dag: extract sshpass_prefix() and ssh_host_key_override_opts() shared
  helpers; ssh_exec_prefix now composes them; add scp_command(local, remote)
  that reuses the SAME two helpers (scp is a distinct binary with the host in
  remote_target, so it cannot compose through command_over_transport's ssh
  prefix — but it shares the posture authority).
- bmc_netboot_serve.dag: bmc_netboot_put_path renders scp_command via the same
  shell.Exec.Run + shell_command_render path as bmc_netboot_run_bmc; the
  extdeps.bmc.ssh import and the whole bmc.Ssh service are deleted.
- Two discriminating witnesses: scp render carries the exact shared posture argv;
  red control asserts no second/forked posture. All bmc_netboot_serve witnesses
  PASS; gate-equivalent compile has zero hard diagnostics.

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

* De-fork BMC scp: trigger-text + discriminating witnesses (review 41797)

Completes the scp de-fork commit: dissolution trigger now names scp_command
(the single ssh/scp posture authority) instead of the deleted bmc.Ssh.PutFile,
and adds two witnesses proving the scp path carries the shared posture argv and
never a second/forked one. All bmc_netboot_serve witnesses PASS.

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

* WIP: srv4 pr

* WIP: srv4 pr

* WIP: srv4 pr

* WIP: srv4 pr

* WIP: srv4 pr

* Accept #7121 deletion of .github/fleet-converge.sh (paper transport retired; FleetConvergeArtifact deregistered)

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

* WIP: srv4 pr

* Regen ci.yml: drop fleet-converge.sh from auto-heal add-list (deregistered in #7121)

The generated ci.yml auto-heal git-add list is derived from the artifact
registry; #7121 removed FleetConvergeArtifact, so the regenerated list no
longer names .github/fleet-converge.sh. Fixes generated_artifact_drift_gate.

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

* WIP: srv4 pr

* Regen ROADMAP.md: restore main's ts-ui-model row + drop trailing blank line (serializer drift)

A bad merge had reverted main's belt-B roadmap row from roadmap_authority.dag;
restored from main. Regenerating with a fresh seed also drops a trailing blank
line the current markdown serializer no longer emits (main's committed copy is
stale, kept green there by the auto-heal job). Fixes generated_artifact_drift_gate.

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

* Merge main + regen artifacts with new-emitter seed (drop ROADMAP.md trailing line)

Branch was behind main's v1_compiler_emit_rust.rs (Lane D #7098); merged main
and rebuilt the seed. Emitted-Rust artifacts now match; ROADMAP.md re-regenerated
without main's stale trailing blank line. Fixes generated_artifact_drift_gate.

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

* WIP: srv4 pr

* Enroll srv4 witnesses in the eligibility census (864 -> 876)

My PR added ~12 witness test entries; main's witness_entry_eligibility_census
(#7111) fail-closes the floor when a witness entry has no census TSV row
(panic at cli_run.rs:8508). Bumped the declared count 864->876, regenerated
the census TSV + histogram, updated the count assertion. Sync + count witnesses
green by execution; the previously-panicking argv_command_render entry is now
present.

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

* Merge main (#7110) + regen census TSV to match merged roster

Kept branch current with main's witness/census churn; regenerated the eligibility
census TSV+histogram so committed == emit(merged roster) (876 entries, emit's
internal roster==count check green). Generated-artifact drift clean.

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

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant