diff --git a/ROADMAP.md b/ROADMAP.md index 10801ed6dfe..719223d238c 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,7 +2,7 @@ `DESIGN.md` is the authority for *why*. This is the **shape of the work** — a scannable, dependency-ordered checklist. **Checkboxes are authoritative for progress**; detail lives in the linked plan docs — don't restate it here (no dual representations). A task's real state is its branch/PR. -Legend: `[x]` done · `[ ]` todo · **indentation = depends on the item it sits under**. Each section opens with a **◆ Milestones** spine — the *verifiable* checkpoints in dependency order (`✓` reached · `▸` now · `○` ahead); the checklist below is the work toward them. Read L→R = the path. +Legend: `[x]` done · `[ ]` todo · ~~struck~~ **superseded →** successor (the named carrier/lane now owns the territory; the row is kept as the pointer, never dispatched) · **indentation = depends on the item it sits under**. Each section opens with a **◆ Milestones** spine — the *verifiable* checkpoints in dependency order (`✓` reached · `▸` now · `○` ahead); the checklist below is the work toward them. Read L→R = the path. **Reset 2026-07-01 (operator-directed).** The roadmap is collapsed to **two pillars** — **§1 get off v1** and **§2 own the compute fabric** — plus **§3 the floor + audit**: the walls that keep both pillars honest, and an execution-grounded audit of what the existing machinery *actually does* (green by execution, red by perturbation). Everything else is **§4 shelved**: parked, not deleted — plan docs and carriers stay, no work dispatches from it, and un-shelving is a PR that moves a node into §1–§3 with a displaced-cost justification (DESIGN §6). The prior roadmap with full detail is in git history. Priority order, top = now. @@ -13,7 +13,7 @@ The operator's real TODO, organized (2026-07-22): six numbered items, each groun **1 · Main to actual green (audit receipts, 2026-07-22):** - [ ] **falsifier dark since 2026-07-16 — roster burn-down** — every 4-hourly cold run red on `non_fold_residue_clean_holds` + `non_fold_residue_no_unrostered_or_stale`, logged as predicted=unaffected / actual=red divergences. Root-caused 2026-07-22 by local receipt (`nfr_roster_receipt`): 3 unrostered sites, 0 stale — `dag/gunbc/host_converge_slice1.dag::host_converge_slice1_host_result_all_valid` + `::host_converge_slice1_host_result_applied_count` (landed #7009) and `dag/gunbc/host_hygiene_reaper.dag::action_kills_build_cache_server` (landed #7026). LANDED with this sheet update: the 3 roster rows (reason + dissolution trigger each, the #6691 shape) are in `cli_run.rs`; receipt `nfr_roster_receipt` unrostered=0 stale=0 and the lens fn evaluates true by execution. The falsifier goes green on its next scheduled run and #7032 auto-closes — if it reds on anything else, that is a NEW find, not this one. — ⏳ awaiting sign-off -- [ ] **srv1 deploy keeps breaking and reds main while the floor is green** — 13 of 2026-07-22's 21 main-run failures are `deploy_dashboard_srv1`, not the floor: `gunbc-tree-sync.service` restart control-process failure (fix in flight: `session/sunny-owl-513`, receipt run 29928424523) after earlier `gunbc-roadmap.service` /healthz ServiceNotReady. Two halves: converge the srv1 units, and decide whether the deploy verdict should share the ci run's conclusion — main-green must mean code-green. The deeper fix is §2's CD-transport node; note `gunbc-roadmap.service` is also item 3's dispatch surface, so this fix is its prerequisite. UPDATE 2026-07-22 late: both halves of the unit fix are in — the tree-sync fix (16:34) and #7077's measured readiness bound (30s→120s; four srv1 starts at 35–39s prove the old bound red every SUCCESSFUL start). The tail executes for the first time on the first main run whose floor passes (post-#7080); check this row off on the first green deploy job, and keep the verdict-sharing question open. FIRST EXECUTIONS (21:49–21:50, both red, DIFFERENT causes — receipts from runs 29957321270/29957141552): (a) the #7077 run died at tree-sync — the .git/ rsync exited 23 (partial transfer) while a SECOND deploy job ran concurrently 18s later on another runner slot against the same /opt/gunbc target; deploy jobs have no concurrency group and ran out of commit order (newer commit deployed first, older second — even on success srv1 converges to the OLDER tree, last-writer-wins). NEW work: serialize the deploy (workflow concurrency group or host-side lock) and stop rsyncing .git/ from a live reusable runner checkout — the CD-transport node's case sharpens. (b) the #7080 run got past tree-sync, restarted the unit (active, 34s into its ~35–39s startup) and probed with the OLD 30s bound — its tree predates #7077; the known class, already fixed. The first honest 120s-bound deploy is the next main run carrying both fixes (#7058 merge, in flight at write time). THIRD EXECUTION (run 29961193892, 22:51): floor green a THIRD consecutive time, deploy red AGAIN at the same tree-sync .git rsync exit 23 — with NO concurrent deploy this time, which RECLASSIFIES the failure from race to a deterministic per-source-checkout condition: succeeded from srv1-03's checkout (21:49), failed twice from srv1-05's (21:49, 22:51). Leading suspect: service-user-unreadable files inside the runner checkout's .git/ (the oneshot reads ghrunner's checkout as User=service-user; a 0600 .git/config carrying the actions auth extraheader would explain exit 23 exactly — and note syncing .git/config to /opt/gunbc would be a CREDENTIAL LEAK if it ever succeeded, so excluding config from the .git sync is both the likely fix and a hardening). LOUDNESS gap, same class the status-tail was added for: the diagnosis shows exit 23 but never the per-file rsync errors (they live in the unit journal) — extend the capture to a journalctl tail so the failing paths are NAMED. The 120s readiness bound remains unexercised until tree-sync converges. RESOLUTION 2026-07-22 late: journal receipt named the root — ONE ghrunner-owned 0600 fetch marker (objects/pack/pack-25d0…keep) unreadable to the unit principal, deterministic on srv1-05; AND /opt/gunbc/gunbc/.git/config was carrying an actions extraheader auth token from the blanket sync (a real credential leak). Operator hand-scrubbed the token and removed the stale marker; the construction fix (whitelist .git sync — HEAD, objects minus fetch transients, packed-refs, refs, terminal exclude wall) MERGED with #7086, making both classes unwritable. Dashboard STAYS on srv1 (operator decision 2026-07-22); the srv3 move was assessed — redeploy-not-migration, ~1–2 days via HostIdentity spec parameterization shared with #7027 G1, plus service-account + claude-auth seeding — and parked. +- [ ] **srv1 deploy keeps breaking and reds main while the floor is green** — 13 of 2026-07-22's 21 main-run failures are `deploy_dashboard_srv1`, not the floor: `gunbc-tree-sync.service` restart control-process failure (fix in flight: `session/sunny-owl-513`, receipt run 29928424523) after earlier `gunbc-roadmap.service` /healthz ServiceNotReady. Two halves: converge the srv1 units, and decide whether the deploy verdict should share the ci run's conclusion — main-green must mean code-green. The deeper fix is §2's CD-transport node; note `gunbc-roadmap.service` is also item 3's dispatch surface, so this fix is its prerequisite. UPDATE 2026-07-22 late: both halves of the unit fix are in — the tree-sync fix (16:34) and #7077's measured readiness bound (30s→120s; four srv1 starts at 35–39s prove the old bound red every SUCCESSFUL start). The tail executes for the first time on the first main run whose floor passes (post-#7080); check this row off on the first green deploy job, and keep the verdict-sharing question open. FIRST EXECUTIONS (21:49–21:50, both red, DIFFERENT causes — receipts from runs 29957321270/29957141552): (a) the #7077 run died at tree-sync — the .git/ rsync exited 23 (partial transfer) while a SECOND deploy job ran concurrently 18s later on another runner slot against the same /opt/gunbc target; deploy jobs have no concurrency group and ran out of commit order (newer commit deployed first, older second — even on success srv1 converges to the OLDER tree, last-writer-wins). NEW work: serialize the deploy (workflow concurrency group or host-side lock) and stop rsyncing .git/ from a live reusable runner checkout — the CD-transport node's case sharpens. (b) the #7080 run got past tree-sync, restarted the unit (active, 34s into its ~35–39s startup) and probed with the OLD 30s bound — its tree predates #7077; the known class, already fixed. The first honest 120s-bound deploy is the next main run carrying both fixes (#7058 merge, in flight at write time). THIRD EXECUTION (run 29961193892, 22:51): floor green a THIRD consecutive time, deploy red AGAIN at the same tree-sync .git rsync exit 23 — with NO concurrent deploy this time, which RECLASSIFIES the failure from race to a deterministic per-source-checkout condition: succeeded from srv1-03's checkout (21:49), failed twice from srv1-05's (21:49, 22:51). Leading suspect: service-user-unreadable files inside the runner checkout's .git/ (the oneshot reads ghrunner's checkout as User=service-user; a 0600 .git/config carrying the actions auth extraheader would explain exit 23 exactly — and note syncing .git/config to /opt/gunbc would be a CREDENTIAL LEAK if it ever succeeded, so excluding config from the .git sync is both the likely fix and a hardening). LOUDNESS gap, same class the status-tail was added for: the diagnosis shows exit 23 but never the per-file rsync errors (they live in the unit journal) — extend the capture to a journalctl tail so the failing paths are NAMED. The 120s readiness bound remains unexercised until tree-sync converges. RESOLUTION 2026-07-22 late: journal receipt named the root — ONE ghrunner-owned 0600 fetch marker (objects/pack/pack-25d0…keep) unreadable to the unit principal, deterministic on srv1-05; AND /opt/gunbc/gunbc/.git/config was carrying an actions extraheader auth token from the blanket sync (a real credential leak). Operator hand-scrubbed the token and removed the stale marker; the construction fix (whitelist .git sync — HEAD, objects minus fetch transients, packed-refs, refs, terminal exclude wall) MERGED with #7086, making both classes unwritable. Dashboard STAYS on srv1 (operator decision 2026-07-22); the srv3 move was assessed — redeploy-not-migration, ~1–2 days via HostIdentity spec parameterization shared with #7027 G1, plus service-account + claude-auth seeding — and parked. — ⏳ awaiting sign-off - [ ] **first NativeRouted flip reverted by receipt — the frontier working as designed** — main run 29963619401 (#7069 merge, srv2-05) redded `emit_on_demand_family_crate_pr_native_agreement_holds` WARM (compile_skipped=true ×3, false in 496ms): a genuine native-vs-eval divergence or member-run failure, NOT cold cache. Remedy per design: complement + meet_join back to `InterpretedRetained agreement_red_on_main` — a two-row data edit, receipt on the carrier (`routed_flip_reverted_note`), investigation off the merge-critical path, falsifier cold control still exercising both legs. Named loudness gap to close BEFORE re-flip: the agreement fn's false carries no located member and no value pair — a divergence receipt must name which member and both answers. - [ ] **queue + zombie hygiene** — ~18 runs/hour arriving against a 60–97-min green wall; main pushes queue behind PR traffic; cancel zombie queued run 50073 (`session/clever-hawk-862`, queued 2026-07-13); revisit main-push priority. - [ ] **overnight main floor breakage healed** — the 00:44–02:04 cluster (DAG compile failure + ci_deploy_sudoers typecheck) was fixed on main by ~02:04; recorded so the day's red accounting separates it from the deploy-tail reds. — ⏳ awaiting sign-off @@ -31,7 +31,7 @@ The operator's real TODO, organized (2026-07-22): six numbered items, each groun **2 · CI actually functional — what it takes, what the roadmap already claims:** - [ ] **definition — CI is functional when (a) a red means a real defect, (b) a green is trustworthy corpus-wide, and (c) the verdict arrives before merge.** Today none of the three hold: deploy reds mask code health (item 1), predict-skip hides corpus reds until the falsifier, and merges land 0–17 min after open while a green run takes 60–97 min. -- [ ] **kill the recurrence class — corpus-scan witnesses predict-skipped** — 4th occurrence per the nfr roster's own dated blocks: hygiene witnesses stamped `SubstrateInputsOnly` while their counters walk the whole corpus, so per-PR selection skips them and only the falsifier reds, days later. Decide once: re-stamp `ReadsLiveTree` (never-predict-skip; sub-ms at floor scale) vs falsifier-red as a merge blocker. Census machinery landed #7070. +- [ ] **kill the recurrence class — corpus-scan witnesses predict-skipped** — 4th occurrence per the nfr roster's own dated blocks: hygiene witnesses stamped `SubstrateInputsOnly` while their counters walk the whole corpus, so per-PR selection skips them and only the falsifier reds, days later. Decide once: re-stamp `ReadsLiveTree` (never-predict-skip; sub-ms at floor scale) vs falsifier-red as a merge blocker. Census machinery landed #7070. 5TH OCCURRENCE (2026-07-23): #7088 landed gate_in_cheap_floor_membership + spec_enrolls_gate unrostered in ci_floor_plan.dag; caught by an unrelated dag-touching PR running the whole-corpus nfr receipt (#7104), backfilled per the roster precedent. - [ ] **CI is not a merge gate (re-evidence)** — 0–17-minute creation→merge latencies observed in the merge wave while a green run takes 60+ min, so verdicts land post-merge and main is the integration testbed; re-evidences §2's merge-admission HELD-state node — while it stays HELD and the falsifier is dark, the corpus has no pre-merge wall at all. - [ ] **floor memory ceiling** — falsifier floor pinned at the 16 GiB cgroup memory.high with ~33 GB swap, sustained PSI stalls, and ~18 min of post-failure residual burn; #7000 (srv3 MemoryHigh/MemoryMax caps) landed 2026-07-22 — confirm the next falsifier runs reflect the caps; residual lineage #6848 → #7030. - [ ] **already claimed in the roadmap — dispatch from these lanes, do not re-plan them**: §0 ① compile wall + ③ affected-set live in CI; §2 floor-throughput group (serial compile-clean wall · shard A ✓ / shard B · within-run double-resolve · resolve-cache default-on) targeting floor <1min; §2 workload-class admission + cap/admission de-conflation; §3 audit rows (affected-set soundness receipts · one tree one verdict · cache honesty re-receipt); the CI-onto-v2 native-routing lane (#7069, parity-gated). What the audit adds is only sequencing: falsifier green first (item 1), then selection honesty, then speed — a fast CI that lies is worse than a slow one. @@ -47,7 +47,7 @@ The operator's real TODO, organized (2026-07-22): six numbered items, each groun **3 · Work intake — dispatch from the roadmap, not ad hoc:** -- [ ] **roadmap-driven dispatch — the machinery is LANDED; three gaps to go-live (assessed 2026-07-22)**: `gunbc serve` on srv1 serves the LIVE roadmap with `POST /dispatch/NODE_ID` invoking `belt_dispatch_node` in-process; the belt observes fail-closed (tmux ls), reconciles the ready frontier, and spawns `git worktree add` + tmux running claude with the FILLED dispatch brief as appended system prompt (effort mapped from node Intricacy), deterministic session UUID, typed refusals throughout; `belt_run_once_json` is the CLI tick for receipts. Gaps: (1) TREE FRESHNESS — srv1's tree/binary have been stale since belt B merged because every deploy failed; unblocks with the first green deploy post-#7086; (2) ONE LIVE END-TO-END RECEIPT — never collected with real claude (tests used a fake): ssh srv1, run belt_run_once_json once, converge whatever typed refusals it names (likely tmux/claude/claude-auth for the service user); (3) SIZED NODES — dispatchability requires intricacy/volume + Accept line + deps-done; the task-sheet authored() rows are unsized tracking rows BY DESIGN, so size the lane nodes you actually want dispatched. Auth precondition: 3b's dispatch-auth row before the button is exposed beyond the tailnet. GO-LIVE RECEIPT (2026-07-23, live on srv1): gap 2 CLOSED by execution — `POST /dispatch/2-dispatch-actuator` → `spawned`; independent read-back: `tmux ls` shows `gunbc-dispatch-2-dispatch-actuator`, worktree at `/opt/gunbc/dispatch-worktrees/2-dispatch-actuator` on branch `dispatch/2-dispatch-actuator`, REAL claude v2.1.170 running with the filled brief (`--effort high`, deterministic session UUID) and its transcript file under `~/.claude/projects/-opt-gunbc-dispatch-worktrees-2-dispatch-actuator/`; second POST → `already_live` (idempotent); bogus node id → `node_not_found` (typed RED, live). One refusal converged: claude's per-path workspace-trust dialog blocked the first spawn (`--dangerously-skip-permissions` does NOT cover it — same finding as ctrl's container entrypoint trust seed); ancestor-dir trust inheritance was proven by execution (seeded parent → child skips the dialog), so the ONE root `/opt/gunbc/dispatch-worktrees` is now seeded in srv1's `~/.claude.json` — interim hand-provisioning of the same class as the host_layout paths, dissolves into the live_deploy membership. Gap 3 receipt: the live ready-set serves 13 sized ready nodes. Gap 1 CLOSED by execution: the #7091 main run (29967907137) went green through the deploy tail — the first green `deploy_dashboard_srv1` post-#7086 — and srv1 converged by independent read: `/opt/gunbc/gunbc` HEAD == main HEAD 960bc8548, binary refreshed, unit active, `/healthz` ok. NEW GAP found live: re-dispatch after Stop is broken — own row below. CLAUDE DEPENDENCY MODELED (2026-07-23, same PR): the trust hand-seed now has a modeled home — `extdeps.llm.cli` carries claude's trust-store facts (`~/.claude.json` projects map, flag `hasTrustDialogAccepted`, ancestor-inheritance; classifier reuses the JSON grammar's string-aware value parser, not a brace scan) and the belt PREFLIGHTS claude-on-PATH + trust-seed-for-worktree-root before any actuation (typed `spawn_failed` steps `claude-cli`/`claude-trust-*` — previously a missing claude spawned a tmux pane that died instantly behind a fabricated `spawned`, and an unseeded root HUNG the session on the dialog); refuse-with-instructions, not auto-seed (the store is claude's own runtime-mutable file — a read-modify-write races the upstream writer), so seeding itself still dissolves into live_deploy. UI FORK FOUND LIVE + FIXED (2026-07-23): the dispatch button read the retired belt-A `ok`/`node` response shape while belt B answers `status`, so EVERY successful click rendered 'failed' (the operator's `5-regen-cutover` click had in fact spawned); the page now derives its ok-predicate from `belt_dispatch_ok_status_labels` — one wire vocabulary with the serve JSON (`belt_dispatch_status_label`), witness-glued to `belt_dispatch_result_ok`, page witness holds a RED on `j.ok`. +- [ ] **roadmap-driven dispatch — the machinery is LANDED; three gaps to go-live (assessed 2026-07-22)**: `gunbc serve` on srv1 serves the LIVE roadmap with `POST /dispatch/NODE_ID` invoking `belt_dispatch_node` in-process; the belt observes fail-closed (tmux ls), reconciles the ready frontier, and spawns `git worktree add` + tmux running claude with the FILLED dispatch brief as appended system prompt (effort mapped from node Intricacy), deterministic session UUID, typed refusals throughout; `belt_run_once_json` is the CLI tick for receipts. Gaps: (1) TREE FRESHNESS — srv1's tree/binary have been stale since belt B merged because every deploy failed; unblocks with the first green deploy post-#7086; (2) ONE LIVE END-TO-END RECEIPT — never collected with real claude (tests used a fake): ssh srv1, run belt_run_once_json once, converge whatever typed refusals it names (likely tmux/claude/claude-auth for the service user); (3) SIZED NODES — dispatchability requires intricacy/volume + Accept line + deps-done; the task-sheet authored() rows are unsized tracking rows BY DESIGN, so size the lane nodes you actually want dispatched. Auth precondition: 3b's dispatch-auth row before the button is exposed beyond the tailnet. GO-LIVE RECEIPT (2026-07-23, live on srv1): gap 2 CLOSED by execution — `POST /dispatch/2-dispatch-actuator` → `spawned`; independent read-back: `tmux ls` shows `gunbc-dispatch-2-dispatch-actuator`, worktree at `/opt/gunbc/dispatch-worktrees/2-dispatch-actuator` on branch `dispatch/2-dispatch-actuator`, REAL claude v2.1.170 running with the filled brief (`--effort high`, deterministic session UUID) and its transcript file under `~/.claude/projects/-opt-gunbc-dispatch-worktrees-2-dispatch-actuator/`; second POST → `already_live` (idempotent); bogus node id → `node_not_found` (typed RED, live). One refusal converged: claude's per-path workspace-trust dialog blocked the first spawn (`--dangerously-skip-permissions` does NOT cover it — same finding as ctrl's container entrypoint trust seed); ancestor-dir trust inheritance was proven by execution (seeded parent → child skips the dialog), so the ONE root `/opt/gunbc/dispatch-worktrees` is now seeded in srv1's `~/.claude.json` — interim hand-provisioning of the same class as the host_layout paths, dissolves into the live_deploy membership. Gap 3 receipt: the live ready-set serves 13 sized ready nodes. Gap 1 CLOSED by execution: the #7091 main run (29967907137) went green through the deploy tail — the first green `deploy_dashboard_srv1` post-#7086 — and srv1 converged by independent read: `/opt/gunbc/gunbc` HEAD == main HEAD 960bc8548, binary refreshed, unit active, `/healthz` ok. NEW GAP found live: re-dispatch after Stop is broken — own row below. CLAUDE DEPENDENCY MODELED (2026-07-23, same PR): the trust hand-seed now has a modeled home — `extdeps.llm.cli` carries claude's trust-store facts (`~/.claude.json` projects map, flag `hasTrustDialogAccepted`, ancestor-inheritance; classifier reuses the JSON grammar's string-aware value parser, not a brace scan) and the belt PREFLIGHTS claude-on-PATH + trust-seed-for-worktree-root before any actuation (typed `spawn_failed` steps `claude-cli`/`claude-trust-*` — previously a missing claude spawned a tmux pane that died instantly behind a fabricated `spawned`, and an unseeded root HUNG the session on the dialog); refuse-with-instructions, not auto-seed (the store is claude's own runtime-mutable file — a read-modify-write races the upstream writer), so seeding itself still dissolves into live_deploy. UI FORK FOUND LIVE + FIXED (2026-07-23): the dispatch button read the retired belt-A `ok`/`node` response shape while belt B answers `status`, so EVERY successful click rendered 'failed' (the operator's `5-regen-cutover` click had in fact spawned); the page now derives its ok-predicate from `belt_dispatch_ok_status_labels` — one wire vocabulary with the serve JSON (`belt_dispatch_status_label`), witness-glued to `belt_dispatch_result_ok`, page witness holds a RED on `j.ok`. — ⏳ awaiting sign-off - [ ] **re-dispatch after Stop is broken — the dispatch loop is one-shot per node (found live 2026-07-23)**: two failure classes, both proven by execution on srv1. (a) DEBRIS — Stop (`tmux kill-session`) leaves the worktree and the `dispatch/` branch behind, so the next POST is a typed `spawn_failed` (step git, `a branch named 'dispatch/…' already exists`); teardown/spawn must own the worktree+branch lifecycle (observe-then-decide, the same upsert_decision shape as session_lease — a worktree with uncommitted work must REFUSE removal, never silently delete). (b) SESSION-ID REUSE — after hand-cleaning worktree+branch, re-dispatch spawns tmux but claude exits 1: `Session ID is already in use` — the deterministic per-node UUID collides with the archived transcript, so a node is one-shot per host at the claude layer too. Fix direction: dedup does NOT depend on UUID determinism (observe keys on the tmux session NAME), so either resume the prior session on re-dispatch (`--resume ` — continues the node's prior work, arguably the RIGHT semantic) or derive a per-attempt UUID; either way the choice must be a typed observation arm, not a fabricated fresh-spawn. RED controls: re-POST after Stop must not be `spawn_failed`; a worktree with uncommitted changes must refuse teardown. - [ ] **until the actuator lands, this sheet is the intake queue** — new work enters as a row here or as a sized lane node with an Accept line, never ad hoc mid-session; dispatch top-down by the numbering; a session that discovers work files a row instead of chasing it. - [ ] **each dispatched item is a real workflow, not a single hop (operator, 2026-07-23)** — stages: MODEL first (the concept/authority delta plus the acceptance claims, in a scratch file or its own PR), BRIEF generated from the row + model with the acceptance bar as checkable claims, IMPLEMENT, ANTAGONISTIC REVIEW against the brief (never against the PR's self-description), LAND with the verdict updating this sheet. The #7087 incident is the pattern to kill: worker hits design gaps, does half, flags the gaps honestly, the PR merges — and the item silently reads done. That is the absorbing fallback at the management layer: cannot satisfy the brief, so land what exists and let merge stand in for completion. The wall: MERGE IS NOT DONE — a merge certifies the diff is safe to land; only a review verdict moves an item's status. @@ -82,14 +82,14 @@ The operator's real TODO, organized (2026-07-22): six numbered items, each groun - [ ] **audit the remaining open PRs and decide each one's disposition** — merge · review-then-merge · fold into another lane · close; the 12 open at snapshot (16:30 UTC) are the children below; re-sweep after the merge wave settles, applying item 4's checklist and item 5's modeling audit to each. - [ ] #7080 layering gate false edges — the reference-derived producer misattributed prelude bare names, binders, and record-literal labels as cross-layer import edges (the one floor red left after #7082); fix verified pre-merge by a local red/green pair (gate witness false on main's tree, true with the PR applied, same tree same witness) — MERGED 2026-07-22 (7c222fc). Also the enabler for closure-derived Group membership (group 5a). — ⏳ awaiting sign-off - - [ ] #7078 §13 alias APPLY as `.dag` workflow (`session/fierce-crab-363`) — ready; clean vs main, no generated artifacts touched, honest placeholder discipline (its equivalence witness is a self-declared scaffold, not the dual-run gate); Rust plan side retained until the real dual-run equivalence receipt. + - [ ] #7078 §13 alias APPLY — CLOSED unmerged 2026-07-23 by the namespace lane as premature: dispatched off the design doc's stale import→alias sequencing; the fresh execution receipt shows the flip is a cheap safe substitution that goes first, making the alias tooling premature. Disposition executed; the doc reconcile rides the namespace lane. — ⏳ awaiting sign-off - [ ] #7077 srv1 deploy readiness fix (was mistitled `dag roadmap work`) — poll bound 30s→120s grounded in measurement: four srv1 starts listening at 35–39s against a 30s bound, so every prior deploy red was the probe quitting ~4s early on a successful start; expectation (40s) and bound (×3 margin) split into separate decls with the demand-scoped-load dissolution trigger — MERGED 2026-07-22 (fec005aa). Residual: `witness_poll_max_attempts_is_thirty` now asserts 120 — rename on next touch. — ⏳ awaiting sign-off - [ ] #7076 right-size the emitted pre-push hook — CI-scale artifact drift gate dropped from GitPrePushHook — MERGED 2026-07-22 (d50e25b). — ⏳ awaiting sign-off - [ ] #7074 cli_run.rs hollowing ledger — CLOSED by operator 2026-07-22, reframed as roadmap description: the census stands as the drain map (867 fns; LensHostBridge 225 + NamespaceResolutionSymbolIndex 214 + AffectedSetSelection 141 = 580/867 — two-thirds of the file on two v2 lanes), while the Python generator and its §3 second-producer question dissolve with the PR. Seed management continues in group 7. — ⏳ awaiting sign-off - [ ] #7072 finish #7043 floor budget refusal on FloorOutcome + plan-roster fact (`session/tidy-ibex-424`) — MERGED 2026-07-22 (44e538d). — ⏳ awaiting sign-off - - [ ] #7069 CI onto v2 — routing frontier + parity gate + consumption P4/P2/R1/R2 (`session/native-routing-consumption`) — operator merging 2026-07-22 after rebase+regen (ci.yml drift collision with the heal merges). Parity windows DEMOTED from flip-precondition to post-flip monitoring (operator re-pricing 2026-07-22: no customers — prefer immediate loud divergence over drip-feed); R2 toolchain-identity key rides its commit 4. Immediate follow-on so it does not pile up: the family re-key row (group 5a); opens the bulk-native arc (group 2a). + - [ ] #7069 CI onto v2 — routing frontier + parity gate + consumption P4/P2/R1/R2 (`session/native-routing-consumption`) — operator merging 2026-07-22 after rebase+regen (ci.yml drift collision with the heal merges). Parity windows DEMOTED from flip-precondition to post-flip monitoring (operator re-pricing 2026-07-22: no customers — prefer immediate loud divergence over drip-feed); R2 toolchain-identity key rides its commit 4. Immediate follow-on so it does not pile up: the family re-key row (group 5a); opens the bulk-native arc (group 2a). — ⏳ awaiting sign-off - [ ] #7068 dissolve cssl_emit_artifact_sanitize v1_rt-strip — dead rule deleted, pub-use-dedupe gap named for crisp-fox-839 — MERGED 2026-07-22 (46127b9). — ⏳ awaiting sign-off - - [ ] #7066 Gate-1 receipt lane B1 — modeled per-module behavioral-receipt producer (`session/nimble-deer-372`) — template body; brief pending. + - [ ] #7066 Gate-1 receipt lane B1 — MERGED 2026-07-23: landed as the full per-module behavioral-receipt producer (one roster + one dispatch; 16 hand-authored transports dissolved). — ⏳ awaiting sign-off - [ ] #7058 post-merge honest frontier re-sweep — generic-T dead, type-ref-import-missing named successor class (`session/sharp-bee-290-roadmap-converge`) — MERGED 2026-07-22 (e89f076); its main run is the first to exercise the deploy tail with both unit fixes in tree. — ⏳ awaiting sign-off - [ ] #7050 computation-identity de-fork census R1–R8 (`session/computation-identity-defork`) — doc + bind row only, clean vs main; merge. R2 (durable native cache toolchain identity) now lands via #7069 commit 4 — the census row stays as its receipt. - [ ] #7027 srv4 BMC onboarding G1–G4 — parameterize per-host, gcloud self-provision, operator-token handler (`session/srv4-onboarding-credential-rotation-gap`) — ready; unblocks srv4. @@ -119,7 +119,7 @@ The operator's real TODO, organized (2026-07-22): six numbered items, each groun **Session branches running CI with no open PR at snapshot:** -- [ ] **each should end as a PR row above or be abandoned deliberately** — `session/sunny-owl-513` (deploy tree-sync fix) · `session/swift-eagle-602` (layering-imports gate P1) · `session/merry-heron-629` (#6985 witness-discovery cascade: pullable() misses arity-zero bare refs) · `session/sleek-crab-621` (fleet_show systemctl via typed extdeps op) · `session/bright-heron-200-work` (exclusion-lane strict-walk closure) · `session/nimble-moth-292-6939` (typed-cache: reference-derived import term in the content key) · `docs/namespace-y-readjudication` (namespace §4 re-adjudication) · `fix/tidy-ibex-merge` (governor fix). +- [ ] **each should end as a PR row above or be abandoned deliberately** — all 8 dispositioned: 7 merged same-day (#7075 · #7060 · #7061 · #7064 · #7059 · #7062 · #7067); fix/tidy-ibex-merge closed via #7073 as a deliberate duplicate-close of the merged #7072 (both pointed at the identical commit; operator-confirmed 2026-07-23). — ⏳ awaiting sign-off ## 0. Priorities — current execution order (rearranged 2026-07-06) @@ -141,23 +141,23 @@ The two pillars — §1 get off v1, §2 own the compute fabric — stand as the Anchor (do not flip-flop): `.dag` = truth; v2 emits its own seed (no stage0 hand-edits); the trust chain is discharged by execution; then the hand-written seed is deleted. Terminal is **hand-written compiler logic → 0**, not zero bytes of Rust: a pinned v2-emitted bootstrap kernel (~8–15k LOC — `claim_executor`, evaluator host-physics, the regen oracle) survives as the content-addressed seed. → [plan](docs/plans/v2-self-hosting.md) · [de-fork audit](docs/plans/dag-v2-defork-audit.md) · [seed census](docs/plans/seed-shrink-census.md) -Ground truth (2026-07-05): `src/v1` = ~174k hand-written `.rs` LOC (the ~154k figure in older docs is stale) + 44 `.dag` files of v1's own modeling; `src/v2` = 874 `.dag`, zero `.rs`. HAND_MAINTAINED roster is down 24 → 7 files + `module_path_index` (~22.3k LOC: the three lens projections drained #6158/#6211/#6212; `phase_profile.rs` ADDED 2026-07-04 with its own dissolution trigger); `patch_*` is fully dead in-tree; the `dag_collect` pair briefly went HAND-only in #6262's regen unbreak, then RETURNED to GENERATED in #6239 (registry authority verified 2026-07-05: `regen_stage0.rs` GENERATED includes the pair, HAND count 7, witness pins 92). The regen gate proves byte-identity per the COMMITTED seed (two-generation): emitter improvements are latent until a cutover, and the cargo-green receipt is episodic (`#[ignore]`, ~3–5min), not continuous — today's walls are byte-identity + the full 92-file byte fixed point (#6218) + well-typed emit. INTERIM (operator-accepted, 2026-07-05): the CI floor's compile-clean step cannot complete inside its 10-minute step budget (#6232; restructured #6273 so a breach fails the STEP loudly instead of cancelling the job silently, and `rust_tests` fits at 30min) while compile-clean runs ~40+min, so these walls are proven by LOCAL execution with documented receipts, not by CI, until the §2 compile-clean work lands. +Ground truth (2026-07-05): `src/v1` = ~174k hand-written `.rs` LOC (the ~154k figure in older docs is stale) + 44 `.dag` files of v1's own modeling; `src/v2` = 874 `.dag`, zero `.rs`. HAND_MAINTAINED roster went 24 → 7 files and has REGROWN to 25 (re-measured 2026-07-23: native-routing shims + governor/pre-push seeds, each with its own dissolution trigger) + `module_path_index` (~22.3k LOC: the three lens projections drained #6158/#6211/#6212; `phase_profile.rs` ADDED 2026-07-04 with its own dissolution trigger); `patch_*` is fully dead in-tree; the `dag_collect` pair briefly went HAND-only in #6262's regen unbreak, then RETURNED to GENERATED in #6239 (registry authority verified 2026-07-05: `regen_stage0.rs` GENERATED includes the pair, HAND count 7, witness pins 92). The regen gate now proves fresh-vs-committed byte-identity unconditionally in CI (#6957/#6958, 98/98 files), so emitter improvements are no longer latent and cargo-green is continuous by composition (see 5-regen-cutover / 5-cargo-green-continuous, closed 2026-07-23) — today's walls are that identity + well-typed emit. INTERIM (operator-accepted, 2026-07-05): the CI floor's compile-clean step cannot complete inside its 10-minute step budget (#6232; restructured #6273 so a breach fails the STEP loudly instead of cancelling the job silently, and `rust_tests` fits at 30min) while compile-clean runs ~40+min, — DISCHARGED since (2026-07-23): compile-clean is CI-scoped per import closure and regen `--verify` is a required CI step, so the walls are CI-proven now. -**◆ Milestones:** front-end ✓ · emit-rust well-typed ✓ · cross-tree import ✓ (#5473) · emitted crate cargo-green, 0 rustc errors ✓ (#5777/#5873, re-verified #6099 — for the THEN-seed; fresh emit is red today, see NOW) · `regen --verify` in CI ✓ (#5873) · interim fixpoint gate, 2-of-92 roster ✓ (#6009) · full-roster 92-file byte-fold + host-grounded digest ✓ (#6218) · v1 self-resolution: #6235 arm fixed ✓ (#6250) · #6241 `get`-registry arm ✓ (#6255, operator-resolved collision) · #6242 comment/registry break ✓ (#6262 — third dark-regen break in four days) · emitter mass fix ✓ (#6243 merged 2026-07-05: the 1667-error fresh-emit red root-caused to ONE `field_is_boxed` predicate bug = 1482 of 1667, plus the 139-error alias-brand/use-line import class; #6266 = byte-identical template hygiene) → **▸ NOW: post-#6243 fresh-emit re-measure receipt → regen cutover #1 (pre-reqs: #6243 ✓ · #6270 registry backfill ✓ · defensive committed-vs-fresh sweep) · HAND queue drain · fixed-point residue (Node-level compare + placeholder hashes)** → seed-honesty (DDC) → **TERMINAL: `src/v1` deleted** +**◆ Milestones:** front-end ✓ · emit-rust well-typed ✓ · cross-tree import ✓ (#5473) · emitted crate cargo-green, 0 rustc errors ✓ (#5777/#5873, re-verified #6099; fresh emit re-greened and byte-identical to the committed seed since #6958) · `regen --verify` in CI ✓ (#5873) · interim fixpoint gate, 2-of-92 roster ✓ (#6009) · full-roster 92-file byte-fold + host-grounded digest ✓ (#6218) · v1 self-resolution: #6235 arm fixed ✓ (#6250) · #6241 `get`-registry arm ✓ (#6255, operator-resolved collision) · #6242 comment/registry break ✓ (#6262 — third dark-regen break in four days) · emitter mass fix ✓ (#6243 merged 2026-07-05: the 1667-error fresh-emit red root-caused to ONE `field_is_boxed` predicate bug = 1482 of 1667, plus the 139-error alias-brand/use-line import class; #6266 = byte-identical template hygiene) → regen `--verify` required in CI ✓ (#6957/#6958 — 98/98 byte-identical fresh-vs-committed) → **▸ NOW: the three-gate v1-deletion bar (dag/gunbc/v1_deletion_plan.dag — emitter fixed point · honest frontier · ledger green)** → seed-honesty (DDC — see the prereq-drift flag on 5-collapse-v1) → **TERMINAL: `src/v1` deleted** -- [ ] **regen-cutover cadence** — absorb latent emitter fixes into the committed seed (#6099 merged with the `machine_width` emit test still ignored: two-generation regen means every emitter improvement is invisible until a cutover). Each cutover un-ignores its witnesses; a stale seed hides emitter regressions. RECEIPT (2026-07-05, local, #6253 — measured on a tree with the `get` sites resolvable; numbers independent of which #6241-gap fix lands, #6255 is the operator-chosen one): regen write-mode completes and materializes the latent backlog — 40 generated files / ~4.3k lines of drift since their last per-file writes — but the fresh crate is cargo-RED: 1667 rustc errors (E0282/E0308/E0425/E0614/E0631; dominant class = #6243's deref-boxing + alias-brand C8 tail). Cutover #1 is BLOCKED on emitter restoration to fresh-emit cargo-green; until it lands, `regen --verify` is red on that drift by construction and every emitter fix stays latent (the broken cutover was measured and NOT committed). UPDATE (2026-07-05 PM): root-caused and largely landed — 1482/1667 (E0308+E0614+E0631) trace to ONE `field_access_field_is_boxed` predicate bug (`is_recursive_type_by_name` fires for types already in `shared_types`, sending Node fields down the deref path), fixed in #6243 (merged), with #6266 as byte-identical template hygiene; the 139 E0425s are the alias-brand/use-line import class (one root, two labels), also carried by #6243. Cutover #1 now waits on: the post-#6243 fresh-emit re-measure receipt (an earlier 1482→0 receipt was measured under a since-retracted fix and must be re-earned) · #6270's `04_method.dag` backfill ✓ merged (7 hand-only #6261 registry rows in the GENERATED seed would otherwise be silently wiped by the regen) · a defensive committed-vs-fresh sweep over the remaining GENERATED files for dark-week hand edits. - - [ ] **real fixed point** — `content_hash` stage1==stage2 over the FULL seed. LANDED (#6218): `source_text_code_unit_digest` host-grounded on `atom_identity_hash`, and the `SelfHostRealizedComparisonGate` byte-fold widened from the 2-file roster to all 92 GENERATED files via the regen manifest (self-updating roster; the gate's INTERIM disposition deleted). REMAINING: the Node-level comparison — emitted compiler Node vs emitted bytes (`generate_stage_candidate_from_ingest` has zero consumers today) — dissolve the `bootstrap.dag` placeholder hashes, and widen the provenance witness off its 1-file roster. This milestone gates the bulk cutover-delete, seed-honesty, and the shelved TS self-host. +- [ ] **regen-cutover cadence — closed by construction (audit 2026-07-23)**: `regen --verify` is a required CI step, green on every main push; #6957/#6958 moved rustfmt normalization to production emit, so all 98 generated files are byte-identical fresh-vs-committed and the two-generation latency this cadence existed to absorb is unwritable. The July-5 cargo-RED/cutover-blocked receipts died with #6243. Forward fixed-point work lives in the v1-deletion plan (^regen_fixed_point_receipt). — ⏳ awaiting sign-off + - [x] ~~**real fixed point** — re-based to the behavioral 2-generation bar (byte-fixpoint an explicit non-goal, #6922/#7092); the landed byte-fold half (#6218) lives on as the required ci_regen gate. Residual the successor does not carry: generate_stage_candidate_from_ingest has zero consumers (candidate_generation.dag).~~ **superseded →** dag/gunbc/v1_deletion_plan.dag ^emitter_fixed_point + ^regen_fixed_point_receipt - [ ] **seed-honesty discharge** (Diverse Double-Compiling) — modeled in `bootstrap.dag` (`SeedHonestyDischarge`), no execution exists; worse, the modeled witness is fail-open by construction (its evidence argument is the same atom it checks against — Holds trivially, no red case constructible) until Stage 3's executing consumer lands. Needs a reproducible artifact to double-compile. Design proposal (second-compiler candidate `ddc_reference_compiler` + computed fixed-point digest, reusing `self_host.dag`'s `canonical_emitted_bytes_digest`; FLAGs A–D open for operator sign-off): [seed-honesty discharge design](docs/plans/seed-honesty-discharge-design.md) - - [ ] **TERMINAL — collapse `src/v1`**: one atomic regen cutover-delete of the 92 GENERATED files (~117k of stage0's ~137k LOC) + per-module test deletes as migration lands + pin the terminal kernel. Requires: HAND queue empty · real fixed point · test-migration green · seed-honesty. -- [ ] **drain the HAND_MAINTAINED queue** (7 files + `module_path_index`, ~22.3k LOC; three lens projections drained ✓ #6158/#6211/#6212 · last `patch_*` dead in-tree ✓ · `phase_profile.rs` added 2026-07-04, dissolution trigger `realization_measurement_loop` Phase 0; the `dag_collect` pair is GENERATED again per #6239, not a HAND drain target — its `std.content_hash` grounding stays tracked by the typed dissolve-on rows in the `.dag` and DESIGN's §3 convergence thread) — remaining dissolution order: `main.rs` flip-back (attempted #6226, self-reverted — the emitter lost Ci-subcommand/`extract_module_path` emission in #6053's dag_collect split; restore the emit gaps first) → `coproduct_reflection` (de-fork-coupled) → `v1_interpreter` pure-eval emit (kernel D [plan](docs/plans/interpreter-kernel-d.md); model+witness landed #6229, phase ModelAndWitnessOnly, blocked on emit_host transport wiring) → `cli_run.rs` (largest, ~12.1k LOC — grew as the absorption point for the drained projections' pure folds per #6211/#6212/#6217; #6046 hard-gates net-new logic INTO it). Host-physics files (`recorded_fixture` · `resolved_graph_cache`) are terminal-kernel pins, not dissolution targets. + - [x] ~~**TERMINAL — collapse src/v1** — the deletion bar lives in the three-gate plan (GateEmitterFixedPoint · GateHonestFrontier · GateLedgerGreen) with frontier.dag (#7058) carrying per-module dispositions. PREREQ DRIFT ruled 2026-07-23 (prereq_drift_ruling_2026_07_23 in v1_deletion_plan.dag, PR #7110): the three gates are the interpreter-deletion bar and correctly omit all three; the terminal claims restore them as GateDeletion bricks — hand_queue_drain before v1_quarantine, test_migration + seed_honesty_decision before v1_delete.~~ **superseded →** dag/gunbc/v1_deletion_plan.dag ^v1_quarantine + ^v1_delete (three-gate bar, #6922/#7092) +- [ ] **drain the HAND_MAINTAINED queue** — re-measured 2026-07-23: 25 files + `module_path_index` (regrown from 7 by pre_push, memory_governor, census_exclude_derive, std_lens_verdict, 3 usv_pilot files, and 10 v2_compiler_* native-routing shims — each landed with its own dissolution trigger; drain as the triggers fire). The cli_run.rs drain has its own plan: [cli_run.rs hollowing, #7084](docs/plans/cli-run-hollowing-plan.md). - [ ] **no-dual-representation-test lens rebuilt pure-v2** (#6104) — lens verdict moves off v1 Rust, the lens-E retirement pattern continued (landed #6104) — ⏳ awaiting sign-off -- [ ] **emit-on-demand execution — prove the artifact path end-to-end** *(operator, 2026-07-07: build this and make sure it actually works, alongside self-hosting)* — the execution model is emit → build → run with content-addressed reuse, never long-lived interpretation: emit a v2 closure to Rust via the seed, build it (sccache-warm), run native, `Share` the artifact by content-hash. First customer: the S1 parse census — `02_parse` + closure emitted once, the census runs native (compiled parser measured LINEAR 1.1ms→13.9ms across 43→6173 words, 2026-07-07 forensics, vs interpreted class-broken pre-fix: 1956w DNF at 900s / 4.35GB RSS — root cause the `length` builtin's O(n) clone-to-count × per-attempt calls = O(n²), interpreter fix in the forensics lane). ACCEPT: (a) same-input interpreted==native agreement witness on the first customer; (b) content-hash reuse receipt — second run pays zero compile; (c) the interpreter's surviving roles named and bounded (bootstrap receipts · compile-time eval), each carrying dissolution trigger = the self-hosting cutover; a NEW long-running interpreted workload is a review reject — route it through emit-on-demand. Interpreter fixes stay scoped to keeping the bootstrap usable, never investment (no bytecode VM, no JIT — closed static substrate ⇒ the AOT artifact dominates; DESIGN §4). +- [x] ~~**emit-on-demand execution** — landed there by execution: kernel #6879, family fanout #6893/#6894/#6895/#6917, native path 9/9 families green + falsifier wet-cadence enrollment #6990, one-build-grain #7042, artifact store #6738; carrier src/v2/std/emit_on_demand.dag. The S1-parse-census first-customer framing is obsolete.~~ **superseded →** witness-realization lane — v1_deletion_plan ^witness_realization_kernel / ^witness_family_fanout · docs/plans/witness-realization-plan.md - [ ] **de-fork dag ↔ v2 grounding cluster** (one std authority — the fixed point must be well-defined over ONE algebra): `algebra` first (LIVE fail-open, 75 floor entries) → effects/float/integer/logic → `nat` LAST. Operator rulings stand: coproduct = structural authority; grounded-realization wins. The cost of not de-forking is no longer theoretical: the `extdeps.shell` dag↔v2 fork silently shadowed `shell.Which` in the two-root module index and kept main red from #6097 until the de-fork hotfix. [brief](docs/plans/dag-v2-defork-audit.md) - [ ] **Root B repoints** — def-unification (coproduct authority + aliases) → repoints (algebra/nat/integer/float/logic/effects/verification) → 🟡-marker dissolution (keystone #5552 merged) - [ ] v1-coupled `coercion`/`node` renames — deferred to v1-delete - [ ] **test-migration lane** — live debt per the `v2.lens.test_migration_debt` shrink-only ratchet: 73 v1 test modules / 731 `#[test]` fns / ~23k LOC with no exact-stem floor witness (baselines 77/912/28546 set 2026-07-02; `pipeline.rs` alone is 417 fns, the dominant unit); the delete-guard blocks removing a v1 test module without its floor witness (hard gate per module, bulk-delete forbidden). **Scrutinize before migrating (operator, 2026-07-05): tests are not inherently valuable — triage each module first (migrate · delete-as-redundant · delete-as-low-value); the guard currently requires an exact-stem witness for ANY delete, so the lane's first deliverable is a typed retirement path through the guard, never a bypass.** Parallelizable now; gates the terminal collapse per module. NOTE: migrated witnesses run on the local discovery path — CI enrollment is opt-in (#6232) until affected-set selection lands. UPDATE (2026-07-05): the typed retirement path LANDED (#6261 — `RetirementDisposition` model, guard union, import-bound `covered_by`), and the first drain tranche merged the same day (#6268/#6270/#6271/#6272: complexity-bounds, transport_emit, scrambled_name, self_gen8 clusters; baselines ratcheted 912→881 fns / 28546→28054 LOC, tightening further at each rebase). Triage finding so far: the delete mass concentrates in the `pipeline.rs`/`parse.rs` batteries (~64% of debt fns); the small-module tail mostly guards real v1 behavior whose dag/std concept exists but is UNWITNESSED — genuine migration work, not deadweight. -- [ ] **emitted crate partition — derive the crate layout, don't hand-draw it** — `stage0_crate_plan()` hand-assigns ~49 modules to `v1_stage0_core` / 7 to `v1_stage0_emit_core` with **zero** references to the module authority (`frontier.dag`): #6677 made the frontier the single authority for module *registration*, but crate *membership* is still a hand ledger — the last uncovered fork in crate organization (§3: a private ledger with no dissolution path). The Rust realization's workflow-layer half of a target-agnostic contract (the shared `CompilationUnit` + `partition_fold` home is the language-consolidation lane's; C is the second realization). Status: design, interface-locked 2026-07-16; implementation owner TBD. [design](docs/plans/emitted-crate-partition-design.md) -- [ ] **make cargo-green continuous (or cheap)** — `route_a_emit_fresh_cargo_green_test` is ignored (~3–5min); an emitter regression that keeps bytes stable per the old seed but breaks a fresh build surfaces late. Decide: fold into `RegenVerifyGate` (doubles its cost) or a scheduled receipt. (This exact failure mode materialized 2026-07-05: fresh emit = 1667 rustc errors, accumulated invisibly while the byte wall was dark — see the regen-cutover receipt.) +- [ ] **emitted crate partition** — derived partition LANDED #6747: v2.workflow.rust_crate_partition grounds on the self-host frontier roster → stage0_crate_partition_generated.dag → consumed by src/v1/stage0_crates.dag, proven by build + regen_verify. Remaining open: the rows are a HandExplicit interim (dissolve-on: PolicyPartition) and interface Node grounding is deferred (stage0_module_dag_interface_grounding debt note). [design](docs/plans/emitted-crate-partition-design.md) +- [ ] **make cargo-green continuous (or cheap)** — resolved by construction, neither named option: post-#6958 the fresh emit is byte-identical to the committed seed (98/98, production-side normalization), the required ci_regen step proves that identity on every main push, and CI builds the committed seed every run — so fresh-emit cargo-green is continuous by composition; the named failure mode (bytes stable per the old seed, fresh build broken) is unwritable. Residual cleanup: route_a_emit_fresh_cargo_green_test still #[ignore] — keep-as-local or delete. — ⏳ awaiting sign-off ## 2. Compute fabric — own the infra (CI · deploy · control plane) @@ -172,21 +172,21 @@ State (2026-07-01): required CI is back on the fleet after the Ubicloud detour ( **Now — correctness of the current posture:** - [ ] **fix the CD transport premise — a deploy needs a target-host proof** — `deploy_dashboard_srv1` is a *srv1 effect*, but job placement is not an srv1 *proof*: `LocalShell` with principal `runner` assumed the runner is ON srv1 (#6093), while `[self-hosted, linux, arm64]` can land on srv2 (and during the Ubicloud window it was a rented VM). A `LocalShell` deploy is valid ONLY when the runner identity proves it is already on srv1 — either pin the job to an srv1-specific trusted runner label, or make the effect `SshShell`-over-tailnet with an explicit srv1 target + typed credential (#6066 Phase 2). Until then every main push gambles the deploy host. — ⏳ awaiting sign-off - - [ ] **stateless frontend MVP on fabric** *(operator directive, 2026-07-01)* — the first **non-CI, product-shaped consumer** of `RunShape → Allocation → Receipt`: point a domain at an IP and serve the process as minimally as possible. Model `SiteArtifact` (digest · media_root · build_recipe) + `WebServiceShape` (cpu/ram/port/stateless/health_path) + `DomainRoute` + `ServiceAllocation`. MVP is intentionally single-site/single-allocation: DNS may be manual (`DnsExternalManual` recorded, not actuated), storage is immutable/content-addressed, compute is a tiny stateless HTTP process, and the receipt proves `/healthz` plus **served artifact digest** — green only when an independent read proves domain → endpoint → process → digest. NO autoscale, NO dynamic user routing, NO DNS/cert automation. Two milestones: **(A)** StaticSite deploy receipt on the current srv1 path — can start now; **(B)** fabric `SiteLease` on the same allocation model as CI — waits for the control-plane read-back. Exists to prove storage+compute+route can be allocated, read back, and retracted through the same apply/receipt pipe as fleet config — a safer fabric consumer than oversubscribed CI (route/supervision/artifact risk, not memory/OOM risk). -- [ ] **roadmap dispatch actuator — dispatch + maintain Claude Code sessions from the srv1 roadmap (simple MVP)** *(operator directive, 2026-07-03 — un-shelves the actuator slice of §4 "roadmap-as-spawner")* — a Dispatch button per READY item that spawns a real `claude` session on srv1 (git worktree + detached tmux + brief seeded from `dispatch_brief_template`), plus GET /sessions / Stop. Reuses `roadmap_spawner` frontier, `session_lease` gating, the emitted-Node-server lane (`node_http_server_emit` grows the dynamic-route/POST handler lane its dissolution trigger already names). Displaced cost: every dispatch today is the operator hand-writing a brief and hand-spawning a session. **Accept (T4):** press Dispatch on one real READY item → a live claude session in a worktree on srv1 working the item, visible in the panel, torn down by Stop; independent read-back = `tmux ls` + transcript file, never our own write; RED: dispatching a non-ready node or a node with a live lease is a typed refusal. Milestones M1–M4 in the plan. [plan](docs/plans/dispatch-maintain-cc.md) + - [ ] **stateless frontend MVP on fabric** — milestone (A) LANDED: roadmap static site served on srv1 (#6128) + healthz REST GET readiness edge (#6753) + bounded read-back (#6769) + roadmap_site_healthz_validate; live_deploy apply/retract on the membership spine (#6814/#6940/#7011). REMAINING: milestone (B) fabric SiteLease on the same allocation model as CI (waits on the control-plane read-back); the public-domain discharge (gunb.ai Pages cutover) is assigned to the site-subsumption lane and has NOT merged yet. +- [ ] **roadmap dispatch actuator** — machinery LANDED and live: first end-to-end dispatch on srv1 by execution (#7096 go-live receipt; belt A #6942 · belt B gunbc serve #6940 · single dispatch authority #6914 · spawn/observe/reap #6836; Dispatch button reads the belt-B status contract; claude preflight typed refusals; independent read-back = tmux ls). REMAINING vs the T4 accept: no Stop verb and no GET /sessions surface (roadmap_serve routes carry only POST /dispatch + statics), and re-dispatch after Stop is one-shot-broken (filed as ts-dispatch-redispatch, sized ready row). [plan](docs/plans/dispatch-maintain-cc.md) - [ ] **workload-class admission model** *(operator directive, 2026-07-01: 1 core → 3 GiB + swap)* — runners are capacity surfaces, not concurrency proof. Define CI workload classes (`floor_light` · `rust_heavy` · `deploy` · `session`) with measured RAM/swap/pids/CPU-token demand; **admitted concurrency per host derives from HostSupply × WorkloadClassDemand, never from runner-slot count**. Initial 128c/125GiB policy: ~42 build tokens per host (≈1 core : 3 GiB, the `ubicloud-standard-16-arm` shape generalized), with intentionally-stranded cores reserved for sessions and low-memory work — stranded is not wasted. Measured anchors: ci ~11GiB · rust_tests ~37GiB peaks vs the old 8G slot caps. **Accept:** admitted concurrency for srv1/srv2 derives by execution from HostSupply × WorkloadClassDemand (witnessed, not hand-set to match), and a proposed allocation whose Σ exceeds supply is REFUSED with a typed verdict — perturb: inflate one class's measured demand and admission shrinks. -- [ ] **cap/admission de-conflation** — three different facts, one knob today: per-slot *containment* (`memory.high` pressure target · `memory.max` hard ceiling · `swap.max` survival ceiling — ceilings, not reservations) vs host *admission* (how many heavy jobs may run) vs in-job *build width* (`CTRL_JOBSERVER_TOKENS` / cargo jobs). The 8GiB fleet slot contract, the 24GiB stopgap, the 37GiB rust_tests peak, and the 42-token host policy are different facts; splitting them is what makes the width fold and budget tree honest (spawn_width already derives from live `memory.max` by construction — the #6107-deferred item was only this split). +- [ ] **cap/admission de-conflation** — re-based 2026-07-23: the three facts now live in three mechanisms — per-slot containment = cgroup caps via converge (#7009/#7000) · host admission = fleet_host_budget conservation (host_allocation_conserves) · build width = the runtime AIMD memory governor (2026-07-12 adaptive-width ruling, which retired the width folds and per-shard byte predictions the original framing assumed). Remaining ask: a receipt that the three mechanisms cover the original knobs with no conflated survivor, or re-home the residue. - [ ] **merge-admission gate: close the HELD state** — wired (#5974/#6080) but the freshness block is HELD pending a real green-on-main receipt, and the #6080→#6101 accidental re-apply/re-revert needs a clean landing. Evidence it is needed: stale-base merges landed BOTH `.gitignore` drift (healed #6110/#6111) AND the `extdeps.shell` collision that kept main red — green-on-branch is not green-on-main. [decision record](docs/plans/ci-merge-freshness.md) **Fabric-hostable rule (operator-signed):** a service is fabric-hostable when it is expressible as **immutable storage + stateless compute + explicit route + read-back receipt**; anything requiring local mutable state is not fabric-portable until its state moves into a `StorageBinding`. "Connect the right users to the right resources" is the fabric's future value, not active work: `RoutePolicy` (nearest/cheapest/least-loaded/trust), multi-replica routes, cert/DNS automation land later, when they hurt — the first version connects ONE domain to ONE admitted allocation and proves it did. **Floor throughput — reduce work, then schedule it (26m → <1min on a typical PR):** -- [ ] **kill the serial compile-clean wall** *(the measured dominant cost — 2026-07-01 receipts from the first Ubicloud main run and its self-hosted twin)* — batch-1 `dag_compile_clean_gate` is ONE node in ONE resolve-group: ~47 of the ~50min step, immune to `spawn_width` (width=9 was live and only parallelizes the ~4min batch-2 tail; same wall on both runner types — the bottleneck is structural, not the host). Levers in leverage order: (a) affected-set-scope the compile-clean to the changed node-closure; (b) cross-run resolve memoization (the per-module resolve cache is within-process only — nothing persists across runs); (c) shard the gate per-module so the width budget finally applies to the dominant node. NOTE the 2026-06-24 profile (26m whole floor) and this receipt (~47min batch-1 alone) disagree — re-profile is part of the §3 audit. +- [ ] **kill the serial compile-clean wall** — re-based 2026-07-23: lever (a) LANDED — per-PR import-closure scoping via tools.dag_compile_clean_scope (2026-07-16) + loader-closure de-fork #6950; the cost picture moved under it (#7001 memory-thrash-not-compute · #6808 sigs-env 2461s→65s, 37.6× · #6999/#7030 namespace-walk fixes; width regime = adaptive governor). Remaining: lever (c) — shard A's compose proof landed but shards were never enrolled in the floor plan (2-compile-clean-shard-b, re-price first); whole-tree baseline runs still pay the serial wall on the falsifier/cold cadence. - [ ] **affected-set de-fork — `v2.lens.affected_set` as single authority** — witness-level run/skip live (#6061, v1 `force_run_all` hack retired); remaining: precompute-skip wired to the same one `.dag` query, the Rust parallel (`NodeFrontierSeeds`) deleted (N→1), and a wall-clock+RSS receipt on a scoped diff. [plan](docs/plans/affected-set-precompute-pruning.md) - [ ] **provenance ingest live at floor runtime** (#6105) — successor lane: resolver S2a + skip-before-resolve remaining fix (PR #6105 closed 2026-07-02 measured work-neutral); node-closure grounding for `v2.lens.affected_set` to be live during the floor pass; gates node-level pruning + the Rust-bridge deletion [plan](docs/plans/affected-set-precompute-pruning.md) - - [ ] **host-scaffold witness classifier de-fork — DONE** (#6224/#6479) — the claim_executor Rust text classifier (`witness_test_fn_uses_live_host_scan`) and the interim `floor:host_scaffold` marker are dissolved into the substrate-declared `LiveTreeDisposition` row (#6479). Placement correction vs this row's original wording: the disposition lives as a `data live_tree_disposition` row in the WITNESS ENTRY FILE (`v2.std.live_tree`), not as a field on `TestClaim` rows — a claim row asserting a foreign entry's liveness would be a second carrier of the same fact (§3 dual representation); the entry's own row is the single authority. Undeclared = ReadsLiveTree = never predict-skip (fail-closed); the nightly affected-set falsifier is the enforcement for lying declarations; call-reachability grade re-derivation is the later lane [plan](docs/plans/affected-set-precompute-pruning.md) -- [ ] **the floor is a full recompute every run** — profiled 26m (2026-06-24): ~518s resolves all 870 witnesses cold, a second ~275s discovery pass, ~360s effect-bound gates, ~134s seed compile; on a one-file PR ~99% of the resolve recomputes witnesses whose inputs did not change. **Target: <1min.** The lever is resolve-phase incrementality, NOT cross-run caching — CI is cold-dominated (the exe-hash re-colds on every code change). + - [ ] **host-scaffold witness classifier de-fork — DONE** (#6224/#6479) — the claim_executor Rust text classifier (`witness_test_fn_uses_live_host_scan`) and the interim `floor:host_scaffold` marker are dissolved into the substrate-declared `LiveTreeDisposition` row (#6479). Placement correction vs this row's original wording: the disposition lives as a `data live_tree_disposition` row in the WITNESS ENTRY FILE (`v2.std.live_tree`), not as a field on `TestClaim` rows — a claim row asserting a foreign entry's liveness would be a second carrier of the same fact (§3 dual representation); the entry's own row is the single authority. Undeclared = ReadsLiveTree = never predict-skip (fail-closed); the nightly affected-set falsifier is the enforcement for lying declarations; call-reachability grade re-derivation is the later lane [plan](docs/plans/affected-set-precompute-pruning.md) — ⏳ awaiting sign-off +- [ ] **floor wall-clock on a scoped PR — target <1min** — the original headline (the floor is a full recompute every run) is discharged: witness-level affected-set selection is LIVE in CI (discovery flip, operator acceptance 2026-07-09; fail-closed selection + falsifier cold control) plus compile-clean closure scoping. The 2026-06-24 profile numbers predate #6848/#6808/#6999 and are void. Target <1min still unmet on cold/whole-tree paths — remaining lever is resolve-phase incrementality, re-based on current receipts. - [ ] **compile-clean shard A — partition boundary + ONE shard + compose proof** — the direct attack on the serial wall (lever c above): identify the module partition boundary for `dag_compile_clean_gate`, run ONE module shard (manually or via minimal wrapper), and prove the shard verdict composes with the existing whole-tree gate (a shard-green ∧ … ∧ shard-green tree is whole-tree green, and a broken module reds its shard). Non-goals: NO floor-plan/scheduler integration, no width tuning. The partition receipt is the deliverable even if enrollment never follows. — ⏳ awaiting sign-off - [ ] **compile-clean shard B — enroll shards in the floor plan** — batch-1 becomes N shard nodes so `spawn_width` finally applies to the dominant cost; before/after batch-1 wall-clock receipt on a real run. Gated on shard A's compose proof. **Accept ([checklist](docs/plans/fleet-acceptance-criteria.md)):** the floor plan CONSUMES the shards (shard A's exemplar is not sharding); every shard derives from the same source-root authority as the whole-tree gate; compose(shards) ≡ the whole-tree verdict on a green tree, a planted bad module fails the composed verdict, an empty roster is Unknown/fail-closed; receipt = before/after batch-1 wall-clock + shard count; RED: drop one shard from the roster → the coverage witness fails. - [ ] **kill the within-run double-resolve** — discovery and execution each resolve the corpus (~275s second pass); execution piggybacks the discovery resolve. Pure within-run win (M1 within-walk memo landed #6008 — this is the cross-phase half). @@ -206,11 +206,11 @@ Receipts + adjacent levers: [fractal Gantt](docs/plans/ci-floor-fractal-gantt.md - [ ] **sound host admission — Σ-accounting with two modes** — post-patch values feed Σ-accounting over RAM, swap, pids, and CPU tokens. **Guaranteed mode**: Σ(memory_max) ≤ RAM budget ∧ Σ(swap_max) ≤ swap budget (safe, conservative). **Burst mode** (the CI target — we trust our jobs): admission from measured class demand + margin, caps as containment ceilings not reservations, and the receipt window must prove admitted×ram_margin+headroom ≤ host_ram, admitted×swap_margin+reserve ≤ host_swap, and oom_kill/swap_fail counters did NOT increase. A plan that passes only by assuming every slot simultaneously consumes its burst ceiling is rejected or explicitly marked Guaranteed-mode. Replaces the too-weak single-slot swap compare that helped sink #6096. **Accept ([checklist](docs/plans/fleet-acceptance-criteria.md)):** admission computes from POST-PATCH desired values (feeding base values instead is a RED); an overcommitted Guaranteed plan fails Σ-accounting by execution; a Burst plan proves its margins; live receipt = one real srv2 window with pre/post `memory.events` showing oom_kill and swap-fail counters did NOT increase. - [ ] **live read, first slice: one runner unit's memory knobs** — read `MemoryMax`/`MemorySwapMax`/`MemoryHigh` for ONE live actions-runner instance and ground the result into the ConvergeTarget semantics (no string flattening). Non-goals: no patch/apply engine, no runner-count reconciliation, no timer. RED: a fixture read that differs from base refuses convergence (`NotConverged`); green receipt: one real srv2 unit read grounded into the model. Stop-and-return if systemctl read output cannot be represented typed. — ⏳ awaiting sign-off - [ ] **live host read seam (full)** — `fleet_show_effective_read` replaces `ReadAbsent` for cgroup caps, runner count, jobserver tokens, swap, and pinned-tree status; synthetic-read witnesses are NOT enough for periodic actuation (the reconciler substrate exists — the live host read is the load-bearing missing piece). The effective base for converge is `host_converge`'s `ConvergeKnob` rows, not `fleet_intent` (physical inventory). Grows knob-by-knob from the first slice above. **Accept (T3/T4 read-side; [checklist](docs/plans/fleet-acceptance-criteria.md)):** live typed reads on BOTH srv1+srv2 covering the runner units (`actions-runner@-*.service`), `MemoryMax`/`MemoryHigh`/`MemorySwapMax`/`TasksMax`/`CPUWeight`, runner count, and the jobserver token value; fixture REDs (absent property → typed Absent · `infinity` where bytes expected → drift · wrong bytes → drift); full-host receipts list EVERY runner unit's effective knobs; NO mutation anywhere in this node; the converge precondition consumes these reads. The first slice does not close this node. - - [ ] **closed-loop converge re-land** — the signed design: base snapshot → edit → **three-way diff** → gated plan → apply → **independent read-back** → commit/retract; **hostname self-selection** (the committed script runs all three hosts' rows unconditionally); **sound host admission** (own node below); runner-width **INCREASE provisioning** (today an echo-to-stderr stub). The three-way-diff carrier does not exist yet in `dag/gunbc/` — and it is a **fold instance, not a bespoke differ** (own node below carries the construction steer; this node's dispatch brief inherits it). **First acceptance case (deliberately narrow, operator-set):** change one srv2 runner-slot memory/swap value — read current → refuse if drifted → apply → read back → commit new base; re-apply is a noop; retract works. **Full acceptance (T4 — operator, 2026-07-02; [12-step checklist](docs/plans/fleet-acceptance-criteria.md)): reconfigure srv1/srv2 to a NEW runner allocation from the model alone** — edit desired (runner width + per-slot memory/swap caps, both hosts) → plan shows exactly the delta → apply per-host → independent read-back proves the new effective values (`systemctl show`, never our own write echoed back) → receipts commit as the new base; a subsequent hand-edit on either host reds the next converge; retract returns both hosts to the prior allocation; the values survive `daemon-reload` and a freshly spawned runner unit inherits them. That, not the narrow first case, is this node's done bar. No Ubicloud inside this PR: just make srv1/srv2 mutable safely. This is the real blocker — until it lands, every fabric model is paper. + - [ ] **closed-loop converge — T4 acceptance on the spine** — re-based 2026-07-23: the three-way-diff carrier EXISTS (host_converge_delta.dag + srv2 ConvergeKnob fixture witness); converge thin-run landed (#6572/#6585/#6598, re-verified 2026-07-20); per-slot MemoryMax convergence generalized multi-unit (#7009) and srv3 caps via host-standup converge (#7000); apply/teardown poles unified on the membership_reconcile spine (#6814) — deploy = one fleet reconcile spine (operator). REMAINING (this node's bar, unchanged): the full T4 accept — reconfigure srv1/srv2 to a NEW runner allocation from the model alone, plan shows exactly the delta, independent read-back (systemctl show, never our own write echoed back), hand-edit reds the next converge, retract restores, values survive daemon-reload ([12-step checklist](docs/plans/fleet-acceptance-criteria.md)); the live read seam is still ReadAbsent (fleet_show_effective_read) — bind ReadObserved at the apply increment. - [ ] **periodic actuation with receipts** — a systemd timer (or ctrl thin-run) executes the emitted converge per-host under the privilege model; receipts land where a hand-edit REDS (G3's unmet promise). Until this exists the emitted shell is spec-without-execution. **Accept (T5; [checklist](docs/plans/fleet-acceptance-criteria.md)):** installed timer on BOTH hosts under the privilege model; per-run receipt (host · model hash · observed hash · applied/noop/conflict · changed knobs) lands where CI/dashboard reads it; a no-change run is a green noop; a hand-edit to a managed cap is DETECTED — auto-correct knobs restore with read-back proof, verify-only knobs (`VerifyOnlyCap` semantics) refuse with a conflict and do not mutate; RED: broken sudo → typed refusal · removed read access → `NotConverged`. A timer existing is not acceptance. - [ ] **runner allocation v0 — srv1/srv2 as StrictLease runner capacity, hand-config retired** *(the operational milestone this control plane exists for — operator, 2026-07-02)* — desired allocation declared in the model per host (runner slots + labels · per-slot `MemoryMax`/`MemoryHigh`/`MemorySwapMax`/`TasksMax` · jobserver tokens), applied by converge, proven by read-back. **Accept (T4, held alive by T5; [checklist](docs/plans/fleet-acceptance-criteria.md)):** every active runner unit on BOTH hosts matches desired effective values by independent read and a freshly started unit inherits the template drop-ins; admitted heavy concurrency derives from the admission model and GitHub cannot schedule past it (labels/slots ARE the backpressure — generic self-hosted labels cannot bypass heavy admission); receipt records host · unit count · labels · effective values · model hash; RED: a hand-edited srv2 cap reds the next converge/receipt · desired heavy concurrency above admission is rejected · wrong/missing label fails the dispatch witness · unprivileged apply refused before mutation; workload proof: one real CI run on the intended shape with no oom_kill increase and peak memory recorded as a measurement row. Not complete while ANY runner-allocation knob on srv1/srv2 requires a hand edit. - [ ] **privilege model for host mutation** — converge writes `/etc/systemd/system/*.d` and runs `systemctl set-property` (root), but #6096's service ran as the operator user with `|| true` swallowing EPERM; extend `DeployAccess`/`host_effect` so an unprivileged apply is a **typed refusal BEFORE mutation**, never a swallowed failure. RED: unprivileged mutation emits no shell / no `host_effect_apply`; green: the privileged modeled path applies in a fixture. — ⏳ awaiting sign-off -- [ ] **three-way diff = the core fold with a lattice codomain — not a new differ** *(operator, 2026-07-01: "is there something inherent to fold/homomorphism that would get us this for free? I'm worried we are reinventing our core mechanism" — confirmed; this node is the construction steer)* — diff is a keyed fold over aligned rows into an algebraic codomain with identity = `Unchanged`: unchanged rows contribute nothing **by the monoid law**, never by filtering — that is the "for free". Structural equality is the degenerate consumer of the same walk (`v2.std.exact_structural_equality_zip_fold` — canonicalize each side, one top-level `==`: an equality verdict is a diff with the hunks discarded; note its internals are canonicalize-then-compare, not a lockstep zip, so the diff fold is a sibling reading, not a call into it); a hunk is the located, typed mismatch coercion already emits (`find_witness` Diagnostics, subject-level locus) collected as data instead of refusing on the first. Three-way is the same fold into a join-semilattice — the `DescentEvidence`/`BoundedLattice` precedent (`dag/std/termination.dag`) with its safety consciously INVERTED: bottom here is the BENIGN `Unchanged`, so the codomain must carry NO Unknown element (an Unknown at bottom would join-fold unreadable state to "no change" — a §5 fail-open; unreadable state is refused upstream at the typed-read wall, never folded) — and `Conflict` = the join of two incomparable changes, so "no mutation on conflict" is **structural** (a plan that reads `Conflict` has no apply arm), not a runtime guard. The inverse laws are the free RED controls (DESIGN §5): `diff(A,A) = identity` · `apply(diff(A,B), A) = B` · retract = the inverse patch — a groupoid, NOT a total `Group`: apply is partial (refuses off-base) and `Conflict` has no inverse; deriving a total apply from Group inhabitance would silently compose through drift. Alignment is free HERE because converge knobs are keyed (a keyed zip is total); general insert/delete tree alignment is a search, explicitly NOT this scope. §3: the change vocabulary EXISTS — `v2.std.change` (`ChangeKind` NodeChanged/NodeAdded/NodeRemoved + projection/artifact arms · `ChangeSet`, already feeding the affected-set lens); attach there or de-fork consciously, never mint a parallel Hunk/Patch — and the algebra anchor picks ONE std authority consciously (`algebra` is pillar-1's FIRST de-fork target, LIVE fail-open; standing ruling: coproduct = structural authority, grounded-realization wins). Layering: the generic keyed-delta/three-way fold is a `std` carrier; `gunbc.host_converge` supplies ONLY the leaf algebra — `ConvergeTarget` keying + per-target normalization/equality across all SIX variants (`SliceProperty` splits apply-value from expected-effective · `PerSlotMemoryCap` byte-normalizes · `RunnerWidth` · `JobserverTokens` · `VerifyOnlyCap` has no apply value at all · `GunbcPinnedTree` converges on pin-coherence, not value equality — one string-equality flattens ALL of that) + apply/retract semantics; live read/apply stays workflow-layer. **Accept (T2 — wired; [checklist](docs/plans/fleet-acceptance-criteria.md)):** (a) law witnesses green with RED perturbs — identity · apply∘diff · inverse-retract · key-reorder invariance · incomparables join to `Conflict`; (b) on real srv2 `ConvergeKnob` fixture rows (base/observed/desired) the plan lists EXACTLY the changed knobs — unchanged knobs absent by the identity law, a drifted knob folds to `Conflict` and no apply arm is reachable from it; (c) `host_converge` computes a REAL converge patch through this carrier — proof by consumption, not grep: remove the carrier and the re-land witness fails to resolve. T4 arrives only via the converge re-land. NOT accepted by: the algebra existing, typechecking, or a hand-rolled compare that happens to agree. +- [ ] **three-way diff = the core fold with a lattice codomain** — accepts (a)+(b) MET by execution: generic keyed fold attached to std.change (#6129, keyed_two_way_diff in dag/std/change.dag; 30 law witnesses incl. identity/reorder/conflict-join) and srv2 ConvergeKnob fixture rows + leaf algebra (host_converge_delta.dag). REMAINING: accept (c) proof-by-consumption — host_converge does not import the carrier (only the witness consumes it); live consumption instead arrived via membership_reconcile (#6814 live_deploy poles, #6820 belt R9) — either re-point (c) to the spine deliberately or wire host_converge through the carrier. - [ ] **service allocation receipt** — independent read-back for frontend services: process running, effective port, route installed, artifact digest served; retract removes route+process. Reuses `reconcile_grounded` (apply → read host back → converge only on observed evidence); failure to read route/process/artifact is `NotConverged`, never success. Generalizes the stateless-frontend MVP's receipt into the fabric's service story. **Accept (T4; [checklist](docs/plans/fleet-acceptance-criteria.md)):** one real service on srv1/srv2 applied AND retracted — read-back proves process · listening port · route · served digest == desired; re-apply is a noop; after retract, read-back proves ABSENCE; RED: right process wrong digest → `NotConverged` · route present but port dead → `NotConverged` · shell exit-0 with failed read-back → `NotConverged`. - [ ] **G3 cgroup caps derived + reconciled** — `TasksMax`/`MemoryMax` are host-set by hand and only *read* live; derive from the budget tree + reconcile via converge so a hand-edit reds. - [ ] **G1 placement** — job→host is GitHub-native, demand-blind, first-idle → heavy runs co-reside while the other host idles. LIVE again since #6111 put required CI back on the fleet; the admission model above is its demand side. [plan](docs/plans/compute-envelope-model.md) @@ -222,13 +222,13 @@ Receipts + adjacent levers: [fractal Gantt](docs/plans/ci-floor-fractal-gantt.md - [ ] **slice 2 — converge thin-run** — implementation MERGED (#6572 keystone `ConvergePlan`+`EmitArtifactThenThinRun`+`converge_apply` · #6585 golden shrink 323→21 lines · #6598 `gunbc converge --host` CLI receiver), operator sign-off PENDING — fleet_converge steady-state interpreted in the binary as a typed plan via `apply()`; emitted bash is the fresh-standup bootstrap fragment + thin invocation lines (supersedes 'emit the whole `.github/fleet-converge.sh`'). FLAGs 2a(i)/2b/2c signed/discharged 2026-07-14 ([census](docs/plans/shell-to-dag-residual-census-and-arc-completion.md) §2); receipts re-verified by execution 2026-07-20 (`fleet_converge_emit`/`fleet_converge_apply` witnesses). Flip to `done: true` + `sign(operator)` on sign-off (mirrors `6-shell-intent-phase1`). [plan](docs/plans/shell-emission-model.md) - [ ] **shell→intent Phase 1 — agnostic orchestration emit** — MERGED (#6832), operator sign-off PENDING — `While`/`BoundedPoll`/general `Retry` (N-level escalation) emit via `05_emit_orchestration` + bash grammar rows; byte goldens `orchestration_*_emit_test`; production consumer `ci_floor_peak_emit.dag`. Flip to `done: true` + `sign(operator)` on sign-off (mirrors `6-shell-slice2`). [plan](docs/plans/shell-intent-emit-realization-design.md) - [ ] **`apply()` Phases B–F** — B `host_exec`→`apply()` (gated on srv3 OsInstalled) · C Redfish live (partially via #6097) · D converge lane = EmitArtifactThenThinRun handler (first ctrl LOC deleted) · E pull-mode self-converge (autoinstall plants the on-host agent; the push star retires) · F decom. Phase A landed (#5756). [plan](docs/plans/host-effect-orchestration.md) - - [ ] **temporal-effect-spine-a — temporal realization spine (T1 vocabulary)** *(operator 2026-07-02; not a workflow engine)* — `std.temporal_effect`: durable facts + `plan_next_step_from_prior_receipt_and_lease` (single prior+lease; list fold is consumer-side); 🟡 markers on stringly receipt labels + derived step id. RED: approval/lease/read-back gates. **Non-goals:** live mutation, DB, scheduler. **Accept (T1):** witness suite green. - - [ ] **srv3-install-reconcile-a — dry-run reconcile entrypoint** *(queued; gated on temporal-effect-spine-a + os-install-deduction-a)* — `InstallAttemptIntent` + workflow steps as data; `srv3_os_install_reconcile` folds preflight + diagnostic + temporal spine; dry-run first. **Accept (T3):** dry-run receipt on srv1 actuator host. - - [ ] **os-install-deduction-a — preflight + KVM diagnostic vocabulary (T1)** *(operator 2026-07-02; deduction half; NOT wired to srv3_os_install_diagnostic until reconcile-a)* — `gunbc.os_install_deduction`: `fold_nbd_proxy_os_install_preflight_verdict` (NBD-proxy/on-ISO actuator scope — NoCloudNet incomplete for this path only), storage policy on payload, `TargetDiskState`, weak KVM verdicts (`KvmFirmwareIdleObserved`, `KvmSuggestsOsBooted`; `OsInstalled` reserved for router read-back). RED: remove storage flips ReadyToBoot; KVM login ≠ OsInstalled. **Non-goals:** live mutation, monitoring product, DB. **Accept (T1):** witness suite green. + - [ ] **temporal-effect-spine-a — temporal realization spine (T1 vocabulary)** *(operator 2026-07-02; not a workflow engine)* — `std.temporal_effect`: durable facts + `plan_next_step_from_prior_receipt_and_lease` (single prior+lease; list fold is consumer-side); 🟡 markers on stringly receipt labels + derived step id. RED: approval/lease/read-back gates. **Non-goals:** live mutation, DB, scheduler. **Accept (T1):** witness suite green. — ⏳ awaiting sign-off + - [ ] **srv3-install-reconcile-a — dry-run reconcile entrypoint** *(queued; gated on temporal-effect-spine-a + os-install-deduction-a)* — `InstallAttemptIntent` + workflow steps as data; `srv3_os_install_reconcile` folds preflight + diagnostic + temporal spine; dry-run first. **Accept (T3):** dry-run receipt on srv1 actuator host. — ⏳ awaiting sign-off + - [ ] **os-install-deduction-a — preflight + KVM diagnostic vocabulary (T1)** *(operator 2026-07-02; deduction half; NOT wired to srv3_os_install_diagnostic until reconcile-a)* — `gunbc.os_install_deduction`: `fold_nbd_proxy_os_install_preflight_verdict` (NBD-proxy/on-ISO actuator scope — NoCloudNet incomplete for this path only), storage policy on payload, `TargetDiskState`, weak KVM verdicts (`KvmFirmwareIdleObserved`, `KvmSuggestsOsBooted`; `OsInstalled` reserved for router read-back). RED: remove storage flips ReadyToBoot; KVM login ≠ OsInstalled. **Non-goals:** live mutation, monitoring product, DB. **Accept (T1):** witness suite green. — ⏳ awaiting sign-off - [ ] **srv3 → OsInstalled** — finish the greenfield install over the solve-driven NBD-proxy actuator (#6097, live BMC); proves the install band end-to-end. [plan](docs/plans/srv3-webui-kvm-virtual-media.md) - - [ ] **resource-namespace-upsert-a — vocabulary only** *(#6134 srv3 bringup follow-up; operator reshape 2026-07-03)* — `std.upsert_decision` (`ObservationVerdict` + `UpsertDecision

`); domain modules `gunbc.file_access`, `gunbc.session_lease`, `gunbc.install_media`. RED: foreign process on 10809=Conflict not kill; outside-namespace chmod=Refuse; drifted seeded ISO plans Remaster not Converged. Non-goal: live srv3 mutation. + - [ ] **resource-namespace-upsert-a — vocabulary only** *(#6134 srv3 bringup follow-up; operator reshape 2026-07-03)* — `std.upsert_decision` (`ObservationVerdict` + `UpsertDecision

`); domain modules `gunbc.file_access`, `gunbc.session_lease`, `gunbc.install_media`. RED: foreign process on 10809=Conflict not kill; outside-namespace chmod=Refuse; drifted seeded ISO plans Remaster not Converged. Non-goal: live srv3 mutation. — ⏳ awaiting sign-off - [ ] **install-media-generic-layer — extract Ubuntu flavor from process** — split `extdeps/os/install_media.dag` generic shapes (fetch/remaster/serve verdicts) from `ubuntu_*` flavor rows; move `.gunbc-content-hash` sidecar + remaster policy to `gunbc/install_media_*`; mandatory before second OS/distro. Post-#6134. - - [ ] **nbd-serve-held-session-lease** — NbdProxyServeSession intent with port/pid/cmdline/ISO/token fingerprint; classification + plan INSTANTIATE `std.upsert_decision` (`ObservationVerdict` + `UpsertDecision

`; domain facts as the P payload — do NOT mint a parallel lease vocabulary, cf. the fork-census 2026-07-03). RED: foreign 10809 no kill; stale matching session drains only. Live consumer: srv3 actuator. + - [ ] **nbd-serve-held-session-lease** — NbdProxyServeSession intent with port/pid/cmdline/ISO/token fingerprint; classification + plan INSTANTIATE `std.upsert_decision` (`ObservationVerdict` + `UpsertDecision

`; domain facts as the P payload — do NOT mint a parallel lease vocabulary, cf. the fork-census 2026-07-03). RED: foreign 10809 no kill; stale matching session drains only. Live consumer: srv3 actuator. — ⏳ awaiting sign-off - [ ] **srv3-boot-action-diagnostic — Redfish vs ipmitool fallback state machine** — separate transports for BmcBootAction; boot refused unless serve RunningExpected; NoRebootObserved → optional IpmiResetFallback with separate approval; OutOfBandHostActionReceipt until modeled. - [ ] **os-install generic naming cleanup** — rename generic behavior tests/modules away from `srv3_*` where testing credential resolution, remaster classification, workflow escalation; keep srv3 only in instance fixtures (`srv3_pre_install_lease_table`, `srv3_seeded_install_media_artifact`). Post-#6134. @@ -246,7 +246,7 @@ Receipts + adjacent levers: [fractal Gantt](docs/plans/ci-floor-fractal-gantt.md - [ ] **the return happened ungated** — #6111 put required CI back on srv1/srv2 by operator call, accepting interim OOM/sccache exposure; the items below are the gates the return *should* have had, now owed as hardening. Ubicloud remains the burst/fallback offer (and the slot-shape template the admission model generalizes). - [ ] **SessionSliceEnforcement + verified-effective caps** — agent-session cgroups have no citable verified-effective cap (the residual over-commit vector on srv1/srv2); the humming apply-rule stands: runner caps must not tighten while sessions are uncapped and oomd is absent. - [ ] **OOM classification consumer** — `ClusteredOutOfMemoryKill` is modeled but absent from the active infra-retry signature roster; build the consumer so an OOM is first-class, never EAGAIN-shaped. [plan](docs/plans/ci-oom-reclassification.md) -- [ ] **resource-aware scheduler (implementation)** — implements the signed [bounded-input / cost-envelope scheduling](docs/plans/bounded-input-cost-envelope-scheduling.md) design: (A) per-shard peak-RSS plumbing → (B) `Runnable.cost` with Predicted `CostEnvelope` → (C) scheduler reads cost, static side-channel deleted → (D) Measured falsifies Predicted, calibration loop retires data rows (#5431 instrument). Construction invariant: more memory → more width → more throughput, no `.dag` edits. [tracker](docs/plans/resource-aware-scheduler.md) +- [ ] **resource-aware scheduler (implementation)** — re-base required: the signed design's authored widths + per-shard peak predictions were deleted by the 2026-07-12 adaptive-width ruling (gunbc_ci_adaptive_width_note) in favor of the runtime AIMD memory governor; the governor's declared dissolve-on is graph-derived per-node demand (CostAccount.space measured — witness-realization measured-space lane, #6738 P1–P6 + #6855 P4 advisory packing width landed). Re-base phases A–C onto governor + measurement lane before dispatching. [tracker](docs/plans/resource-aware-scheduler.md) - [ ] **resource budget tree** — admission (construction) · conserve-lens (honest residue) · runtime reconcile (fail-closed handler), three verdicts never conflated; subsumes spawn-width/placement/compile-jobs as consumer leaves. Protective only when paired with an enforcement actuator (cgroup `memory.max`, operator-fenced). [carrier](dag/product/budget_tree.dag) [grounding](docs/plans/budget-tree.md) - [ ] **one Placement authority** — jobs (GitHub) · threads (`spawn_width`) · sessions (ctrl capacity) are 3 forks of "put work on a host"; `Placement`/`Materialization` are modeled but inert — CI consuming them is the lane's real deliverable. @@ -258,12 +258,12 @@ Both pillars ride the CI floor: tree-wide marker-driven witness discovery · com **Audit — green by execution, red by perturbation:** -- [ ] **affected-set lens** *(the operator's named example)* — witness-level skip is LIVE on the floor (#6061); prove it: (a) **soundness** — construct a diff that MUST re-run a witness and assert it runs (a skipped-but-affected witness is the fail-open catastrophe); (b) **effectiveness** — receipts on real scoped diffs (skip counts + wall-clock delta, not claims); (c) **fail-closed default** — a provenance gap falls back to run-all, witnessed RED-on-perturb. The node-closure half (#6105) inherits the same receipt obligation before it may prune. +- [ ] **affected-set lens — discharged by a standing mechanism (audit 2026-07-23)**: (a) soundness = the 4-hourly falsifier runs the corpus cold with predictions recorded, counted divergence is the RED — and it discriminated live (the 07-16..07-21 red period was real roster gaps, healed #7083; alert loudness #7022); (b) effectiveness = discovery-flip receipt 8→~1,721 witnesses/PR (ci_spec_discovery_flip_note, operator acceptance 2026-07-09) + regen affected-set ~4m45s/PR (#6732) + compile-clean closure scoping (#6658); (c) fail-closed = #6525 ReadsLiveTree never-skip and a provenance gap REFUSES, never widens (the original run-all wording predates the §5 absorbing-fallback ruling). — ⏳ awaiting sign-off - [x] **mechanism inventory with red-controls** — census every wired gate/lens/cache (floor-plan roster + `commit_workflow`): what it claims · its discriminating RED witness · its last execution receipt. Anything without a red-control gets one or gets demoted/deleted. The inert-lens backstop (#5433) covers *wiring*; this covers *claim-vs-behavior*. [plan](docs/plans/mechanism-inventory-red-controls.md) — ✓ signed off: operator - [ ] **cache honesty re-receipt** — re-run the warm==cold purity oracle against CURRENT main (616/616 was pre-reset), and close the sccache exit-0-no-binary class (below); a cache that lies is worse than no cache. - [ ] **artifact-freshness gate** *(operator ask: "we need a freshness gate, if we don't already have one")* — we half-do: the per-PR drift gate proves committed==emitted for the PR's OWN tree, but drift still LANDED on main (`.gitignore` stale vs its authority since #6097; found and healed by #6110/#6111) because admission never re-validates against CURRENT main — green-on-branch is not green-on-main. The closing mechanism is the §2 merge-admission freshness block (HELD); this item is its receipt pair: (a) reproduce the landed-drift path as a RED witness, (b) confirm the freshness block refuses it once un-HELD. -- [ ] **one tree, one verdict** — 2026-07-01 live finding: `dag_compile_clean_gate` was GREEN while the discovery-corpus resolve of the same tree was RED (`extdeps.shell` module collision, silent last-root-wins shadowing; de-fork + loud-collision wall shipped as the hotfix). Two resolve paths gave two verdicts on one corpus — enumerate every place a module index is built, and make their collision/ordering semantics ONE authority so a gate cannot be green on a tree the floor cannot resolve. -- [ ] **enforcement intent + model-quality walls** *(operator-directed 2026-07-02; §3 un-shelve — displaced cost: repeated manual "what is enforced, by what lens, over what corpus" joins; CI-killing quadratics; repeated dual-representation/anemia rediscovery)* — model the operator's recurring standing directives as durable `StandingIntent` rows and gate the relationship (intent ⇄ `LensContract` ⇄ `CoverageReceipt`) fail-closed, so a mechanism *claiming* enforcement is complete only when the gate proves the claim **from receipts, not self-declared contract claims**. One new authority (`StandingIntent`); everything else extends existing machinery (`LensRegistryEntryV0` → `LensContract`; reuse `ConstructionJustification` / `subject_roster`; consume `intent_linearity` / `self_applying_lenses`). Anti-overcomplication: no lens may claim *repo-wide* / *blocking* / *complete* / *self-applying* unless the gate can prove it. Rollout: rows live; gate Blocking on contract consistency; object rules AuditOnly until receipts land. Children, A→C before object rules D/E: **A** StandingIntent carrier + LensContract extension (`ConsumerKind`/`ConsumerRequirement` NOT hardwired to `FloorGate`; `EnforcementMode` order `Advisory < AuditOnly < Blocking` modeled) · **B** enforcement_intent_gate contract-consistency reds (over `CoverageReceipt`s) · **C** complexity.repo-wide first proof (3 legs red today, no `decl_facts` dep) · **D** complexity R1 accumulator-in-copied-port object rule (HOLDS behind #6155) · **E** anemia/consolidation first model-quality consumers (suggest a consolidation target, not just warn). [design](docs/plans/enforcement-intent-design.md) +- [x] ~~**one tree, one verdict** — the concrete forks dissolved: #6950 gate loader runs both closures (the exact gate-green/floor-red fork), #6935 reference_resolution_facts builtin de-forked the module-graph host; the systemic one-resolution-authority ask IS the namespace lane. Residual to carry: the gate-equivalent local invocation is still flag-sensitive (--dependency-pool-index primary-precedence).~~ **superseded →** namespace-only resolution lane (operator-signed 2026-07-06) — docs/plans/namespace-resolution-design.md +- [ ] **enforcement intent + model-quality walls** — substantially LANDED, re-based 2026-07-23: carrier family src/v2/lens/enforcement/ (standing_intent, contract, gate, receipts) + enforcement_live.dag on main; children A+B via #6756 (Question-0 lens-module gate, StandingIntent fail-closed); C carrier standing_intent_complexity_repo_wide exists; D's object rule effectively landed (#6527 accumulator-copy as required root-grain compile lens + #6540); E first consumer merged (model_anemia lens). Post-landing churn: #7070 de-enrolled lens_module_gate from the compile door (corpus-grain invariant, tree-grain roster). REMAINING: fold that churn in, finish the C receipts, close the DESIGN open thread. [design](docs/plans/enforcement-intent-design.md) **Cost / risk / benefit — the floor's unmodeled optimization:** @@ -271,9 +271,9 @@ Both pillars ride the CI floor: tree-wide marker-driven witness discovery · com **Open floor holes:** -- [ ] **nightly full-corpus selector-backstop** — per-PR selection is only sound because nightly runs everything; ⚠ CI-gen load-bearing +- [ ] **full-corpus selector-backstop — live at 4-hourly cadence (audit 2026-07-23)**: falsifier.yml cron runs the corpus cold with predictions recorded (the flip note names it the selection's soundness governor); falsifier-alert (#7022) closes the silent-red loudness gap; green again per #7083. Regen's cold control is separate (unconditional main-push regen). — ⏳ awaiting sign-off - [ ] **tree-scoped builtin registry** (fail-closed) — the global seed registry leaks intrinsics into the substrate compile, making compile-clean falsely green; instance fix #5452, class fix (partition) open [force-check plan](docs/plans/compile-clean-forcecheck.md) -- [ ] **kill sccache false-greens** — exit-0-no-binary; build-verify asserts the artifact exists + is fresh (partly landed in `ci.yml`) +- [ ] **kill sccache false-greens** — exit-0-no-binary CLOSED: claim_executor --verify-build-artifacts asserts every declared release binary exists + is executable at 3 ci.yml sites (#6472-era); deploy rebuild-flake killed by artifact reuse (#6810). REMAINING residue: freshness not asserted; sccache local-disk content_verified_on_read=false with live repro (#7031 — the cache-lies class is confirmed live); the ci_spec absorbing retry-fallback removal is srvN build-cache STEP-2, gated on srv1 (STEP-1 #6835). ## 4. Shelved (parked 2026-07-01 — not deleted) @@ -282,16 +282,22 @@ Every lane below was live roadmap before the reset. Shelved = plan docs and carr - **fold-ergonomics lane** — inert-abstraction lens · non-fold-residue audit · staging combinator · ban source comments [charter](docs/plans/fold-ergonomics.md) [residue catalogue](docs/plans/non-fold-irreducible-residue-catalogue.md) [debt sample audit](docs/plans/real-debt-syntactic-sample-audit.md) [eval-bind PROPOSE](docs/plans/eval-bind-node-eval-propose.md) - **fail-closed meta band** — `Value::Null` split (the deep root) · Disposition carrier · reference grounding · cardinality refinement · expressibility frontier · reachability-completeness lens · axiom+syllogism lens · self-applying lenses · inert-lens promotion + gate-hygiene residue [lockdown](docs/plans/fail-closed-lockdown.md) [fork plan](docs/plans/model-realization-fork.md) [Disposition](docs/plans/disposition-carrier.md) [reference grounding](docs/plans/reference-grounding-migration.md) [cardinality](docs/plans/cardinality-refinement.md) [P1 where-lowering](docs/plans/p1-where-clause-lowering.md) [frontier](docs/plans/expressibility-frontier.md) [inert-layer lens](docs/plans/inert-layer-lens.md) [axiom lens](docs/plans/axiom-syllogism-lens.md) [self-applying](docs/plans/self-applying-lenses.md) [construction rule](docs/plans/construction-justification-rule.md) - **rust-gate `.dag`→rust coverage wall (edge-b)** + stage0 clone-census ratchet [brief](docs/plans/edge-b-rust-dag-provenance-brief.md) -- **complexity budget whole-codebase** + the algebraic-rewrite construction engine (O(n²)→O(n) catalog, `Unknown` dissolution) [rewrite plan](docs/plans/algebraic-rewrite-optimization.md) + +- [x] ~~**complexity budget whole-codebase** — un-shelved and live in tree; the algebraic-rewrite construction engine remains parked ([rewrite plan](docs/plans/algebraic-rewrite-optimization.md)).~~ **superseded →** live complexity-enforcement carriers — #6527 accumulator-copy required compile lens · #6540 affected-set floor enforcement · #6632 per-op cost derivation + - **testgen oracle + wiring-liveness family** (compile-time wiring lens ✓ #5679 · pre-send guard ✓ #5683 stand; the generator/preflight expansion parks) [method](docs/plans/testgen-oracle.md) [wiring](docs/plans/wiring-liveness-preflight.md) - **caching completion** — `realize(subject)` one door (P2) · M5 fixture-store · native `content(T)` (P5) · B1 generic-instantiation / B2 cross-tree content-hash blockers · one Materialization kernel · shared secrets model [loop](docs/plans/realization-measurement-loop.md) [M4](docs/plans/m4-universal-hermetic-corpus.md) [M5](docs/plans/m5-fixture-store-consolidation.md) - **CI inline-shell de-fork · interpreter terminal-output de-fork** (seed forks of modeled authorities; both shrink as v1 burns down) [emission-ingestion](docs/plans/emission-ingestion-inverse.md) - **idea machine** — ingest-at-large · English closure/round-trip · cross-media (JSON/react/diagram) · `Medium` homomorphisms · format-model C4–C6 · fidelity compose-up · eval generalization · invert-hand-maintained residue [plan](docs/plans/idea-machine.md) [format reconciliation](docs/plans/format-model-reconciliation.md) [invert](docs/plans/invert-hand-maintained.md) -- **shell-emission slices 3–4 (census-rescoped)** — live_deploy → thin-run/typed-effect candidate (runtime-present; not a golden to freeze) · bmc_token_federation (two Do rows) → ci_workflow RunSteps → githooks thin shim [plan](docs/plans/shell-emission-model.md) + +- [x] ~~**shell-emission slices 3–4** — absorbed: #6750 routed bmc_token_federation Do rows + ci_workflow RunSteps through orch_emit_step; githooks thin shim in tree; live_deploy re-modeled on the fleet-reconcile spine (#6820/#7086), not a frozen golden.~~ **superseded →** shell→intent arc — DESIGN open thread + docs/plans/shell-to-dag-residual-census-and-arc-completion.md + - **TypeScript first-class emit + TS self-host** — END GOAL UNCHANGED (both realizations, per plan do-not-relitigate); resumes after the Rust fixed point [gap census](docs/plans/typescript-gap-census.md) - **language-target self-host frontier** — the get-to-self-host path for all emission languages (Rust as model; Verilog/SPICE/LLVM as design-stress falsifiers); solve resolved as higher-order not a primitive [frontier](docs/plans/language-target-self-host-frontier.md) [solve rationale](docs/plans/solve-higher-order-design.md) -- **HTML/React + live dashboard lane** — page ✓ (#6010) and srv1 deploy ✓ (#6030) keep running as-is; interactivity · idea-input · demo park. The minimal **stateless-frontend fabric slice is active in §2** only as a storage+compute+route consumer, not as the full dashboard/product lane (the CD *transport* fix is also §2 live work) -- **session dashboard + roadmap-as-spawner** — the *automatic* spawn bridge stays fail-closed paused; §1–§3 sized nodes are the only dispatch surface (§3 audit items are deliberately dispatchable — the operator's audit lanes). The operator-clicked **dispatch actuator** slice is un-shelved into §2 (2026-07-03) [plan](docs/plans/roadmap-spawner.md) + +- [x] ~~**HTML/React + live dashboard lane** — both halves now owned elsewhere: the page/frontend by the site-subsumption lane; the blessed keep-running JS server is a named §3 dual representation slated for deletion by belt B.~~ **superseded →** gunb.ai site-subsumption lane (#6927 Phase-0) + gunbc-served dashboard (belt B, #6940) +- [x] ~~**session dashboard + roadmap-as-spawner** — the operator-clicked dispatch actuator became the conveyor belt and is LIVE. Still true from this row: the automatic spawn bridge stays fail-closed paused.~~ **superseded →** conveyor-belt lane — belt A+B merged (#6940), belt_dispatch_node single dispatch authority (#6914), go-live #7096 + - **gunbhub** (own the Git/CI engine, closes G6) · internal repo model · compute fabric as a sellable piece - **privacy / isolation model for the compute fabric** — trust boundaries, tenant isolation, what the fabric may observe about a workload; was compute-fabric downstream work pre-reset, parked here so it is not lost (`trust_class` on `RunShape` is its active §2 seam). Includes committed-secret references (operator 2026-07-02, not urgent): a typed `SecretRef` — GCP Secret Manager resource name + version/content-hash — so sensitive facts (router serial, WAN MAC, public prefixes, credentials) commit as model-legible references while values stay in Secret Manager; redaction by construction (public shapes carry no raw-value field); first consumer: the network-identity observation fixtures. - **structural correctness walls (standing, not active)** — generated-output gate · coproduct exhaustiveness · cross-representation equality · oracle-method map; they keep gating, no expansion work dispatches from here diff --git a/dag/gunbc/roadmap_authority.dag b/dag/gunbc/roadmap_authority.dag index 87eb46035c2..d1014e4fb0c 100644 --- a/dag/gunbc/roadmap_authority.dag +++ b/dag/gunbc/roadmap_authority.dag @@ -9,7 +9,7 @@ import gunbc.roadmap_model { NodeSizing, Unsized, Sized, SectionElement, section_prose, section_group, } -import gunbc.roadmap_status { RoadmapItem, DerivableLine, AuthoredLine, PlainLine, Signoff, Unsigned, SignedOff } +import gunbc.roadmap_status { RoadmapItem, DerivableLine, AuthoredLine, PlainLine, SupersededLine, Signoff, Unsigned, SignedOff } import std.markdown { MarkdownBlock, HeadingBlock, ParagraphBlock, TextInline, H1 } import extdeps.languages.markdown { serialize_markdown_source } @@ -72,6 +72,10 @@ fn authored_wi(id: String, done: Bool, content: String, intricacy: Intricacy, vo } } +fn superseded(id: String, by: String, content: String) -> RoadmapNode { + RoadmapNode { node: nid(s: id), line: SupersededLine { by: by, content: content }, carriers: [], sizing: Unsized, owner: "", signoff: Unsigned } +} + fn owned(rn: RoadmapNode, owner: String) -> RoadmapNode { RoadmapNode { node: rn.node, line: rn.line, carriers: rn.carriers, sizing: rn.sizing, owner: owner, signoff: rn.signoff } } @@ -88,7 +92,7 @@ fn preamble() -> List { [ HeadingBlock { level: H1, inlines: [TextInline { text: "gunbc — Roadmap" }] }, ParagraphBlock { inlines: [TextInline { text: "`DESIGN.md` is the authority for *why*. This is the **shape of the work** — a scannable, dependency-ordered checklist. **Checkboxes are authoritative for progress**; detail lives in the linked plan docs — don't restate it here (no dual representations). A task's real state is its branch/PR." }] }, - ParagraphBlock { inlines: [TextInline { text: "Legend: `[x]` done · `[ ]` todo · **indentation = depends on the item it sits under**. Each section opens with a **◆ Milestones** spine — the *verifiable* checkpoints in dependency order (`✓` reached · `▸` now · `○` ahead); the checklist below is the work toward them. Read L→R = the path." }] }, + ParagraphBlock { inlines: [TextInline { text: "Legend: `[x]` done · `[ ]` todo · ~~struck~~ **superseded →** successor (the named carrier/lane now owns the territory; the row is kept as the pointer, never dispatched) · **indentation = depends on the item it sits under**. Each section opens with a **◆ Milestones** spine — the *verifiable* checkpoints in dependency order (`✓` reached · `▸` now · `○` ahead); the checklist below is the work toward them. Read L→R = the path." }] }, ParagraphBlock { inlines: [TextInline { text: "**Reset 2026-07-01 (operator-directed).** The roadmap is collapsed to **two pillars** — **§1 get off v1** and **§2 own the compute fabric** — plus **§3 the floor + audit**: the walls that keep both pillars honest, and an execution-grounded audit of what the existing machinery *actually does* (green by execution, red by perturbation). Everything else is **§4 shelved**: parked, not deleted — plan docs and carriers stay, no work dispatches from it, and un-shelving is a PR that moves a node into §1–§3 with a displaced-cost justification (DESIGN §6). The prior roadmap with full detail is in git history. Priority order, top = now." }] }, ] } @@ -113,24 +117,24 @@ fn section_1() -> RoadmapSection { title: "1. Get off v1 — v2 self-hosts (TERMINAL: `src/v1` deleted)", elements: [ section_prose(content: "Anchor (do not flip-flop): `.dag` = truth; v2 emits its own seed (no stage0 hand-edits); the trust chain is discharged by execution; then the hand-written seed is deleted. Terminal is **hand-written compiler logic → 0**, not zero bytes of Rust: a pinned v2-emitted bootstrap kernel (~8–15k LOC — `claim_executor`, evaluator host-physics, the regen oracle) survives as the content-addressed seed. → [plan](docs/plans/v2-self-hosting.md) · [de-fork audit](docs/plans/dag-v2-defork-audit.md) · [seed census](docs/plans/seed-shrink-census.md)"), - section_prose(content: "Ground truth (2026-07-05): `src/v1` = ~174k hand-written `.rs` LOC (the ~154k figure in older docs is stale) + 44 `.dag` files of v1's own modeling; `src/v2` = 874 `.dag`, zero `.rs`. HAND_MAINTAINED roster is down 24 → 7 files + `module_path_index` (~22.3k LOC: the three lens projections drained #6158/#6211/#6212; `phase_profile.rs` ADDED 2026-07-04 with its own dissolution trigger); `patch_*` is fully dead in-tree; the `dag_collect` pair briefly went HAND-only in #6262's regen unbreak, then RETURNED to GENERATED in #6239 (registry authority verified 2026-07-05: `regen_stage0.rs` GENERATED includes the pair, HAND count 7, witness pins 92). The regen gate proves byte-identity per the COMMITTED seed (two-generation): emitter improvements are latent until a cutover, and the cargo-green receipt is episodic (`#[ignore]`, ~3–5min), not continuous — today's walls are byte-identity + the full 92-file byte fixed point (#6218) + well-typed emit. INTERIM (operator-accepted, 2026-07-05): the CI floor's compile-clean step cannot complete inside its 10-minute step budget (#6232; restructured #6273 so a breach fails the STEP loudly instead of cancelling the job silently, and `rust_tests` fits at 30min) while compile-clean runs ~40+min, so these walls are proven by LOCAL execution with documented receipts, not by CI, until the §2 compile-clean work lands."), - section_prose(content: "**◆ Milestones:** front-end ✓ · emit-rust well-typed ✓ · cross-tree import ✓ (#5473) · emitted crate cargo-green, 0 rustc errors ✓ (#5777/#5873, re-verified #6099 — for the THEN-seed; fresh emit is red today, see NOW) · `regen --verify` in CI ✓ (#5873) · interim fixpoint gate, 2-of-92 roster ✓ (#6009) · full-roster 92-file byte-fold + host-grounded digest ✓ (#6218) · v1 self-resolution: #6235 arm fixed ✓ (#6250) · #6241 `get`-registry arm ✓ (#6255, operator-resolved collision) · #6242 comment/registry break ✓ (#6262 — third dark-regen break in four days) · emitter mass fix ✓ (#6243 merged 2026-07-05: the 1667-error fresh-emit red root-caused to ONE `field_is_boxed` predicate bug = 1482 of 1667, plus the 139-error alias-brand/use-line import class; #6266 = byte-identical template hygiene) → **▸ NOW: post-#6243 fresh-emit re-measure receipt → regen cutover #1 (pre-reqs: #6243 ✓ · #6270 registry backfill ✓ · defensive committed-vs-fresh sweep) · HAND queue drain · fixed-point residue (Node-level compare + placeholder hashes)** → seed-honesty (DDC) → **TERMINAL: `src/v1` deleted**"), + section_prose(content: "Ground truth (2026-07-05): `src/v1` = ~174k hand-written `.rs` LOC (the ~154k figure in older docs is stale) + 44 `.dag` files of v1's own modeling; `src/v2` = 874 `.dag`, zero `.rs`. HAND_MAINTAINED roster went 24 → 7 files and has REGROWN to 25 (re-measured 2026-07-23: native-routing shims + governor/pre-push seeds, each with its own dissolution trigger) + `module_path_index` (~22.3k LOC: the three lens projections drained #6158/#6211/#6212; `phase_profile.rs` ADDED 2026-07-04 with its own dissolution trigger); `patch_*` is fully dead in-tree; the `dag_collect` pair briefly went HAND-only in #6262's regen unbreak, then RETURNED to GENERATED in #6239 (registry authority verified 2026-07-05: `regen_stage0.rs` GENERATED includes the pair, HAND count 7, witness pins 92). The regen gate now proves fresh-vs-committed byte-identity unconditionally in CI (#6957/#6958, 98/98 files), so emitter improvements are no longer latent and cargo-green is continuous by composition (see 5-regen-cutover / 5-cargo-green-continuous, closed 2026-07-23) — today's walls are that identity + well-typed emit. INTERIM (operator-accepted, 2026-07-05): the CI floor's compile-clean step cannot complete inside its 10-minute step budget (#6232; restructured #6273 so a breach fails the STEP loudly instead of cancelling the job silently, and `rust_tests` fits at 30min) while compile-clean runs ~40+min, — DISCHARGED since (2026-07-23): compile-clean is CI-scoped per import closure and regen `--verify` is a required CI step, so the walls are CI-proven now."), + section_prose(content: "**◆ Milestones:** front-end ✓ · emit-rust well-typed ✓ · cross-tree import ✓ (#5473) · emitted crate cargo-green, 0 rustc errors ✓ (#5777/#5873, re-verified #6099; fresh emit re-greened and byte-identical to the committed seed since #6958) · `regen --verify` in CI ✓ (#5873) · interim fixpoint gate, 2-of-92 roster ✓ (#6009) · full-roster 92-file byte-fold + host-grounded digest ✓ (#6218) · v1 self-resolution: #6235 arm fixed ✓ (#6250) · #6241 `get`-registry arm ✓ (#6255, operator-resolved collision) · #6242 comment/registry break ✓ (#6262 — third dark-regen break in four days) · emitter mass fix ✓ (#6243 merged 2026-07-05: the 1667-error fresh-emit red root-caused to ONE `field_is_boxed` predicate bug = 1482 of 1667, plus the 139-error alias-brand/use-line import class; #6266 = byte-identical template hygiene) → regen `--verify` required in CI ✓ (#6957/#6958 — 98/98 byte-identical fresh-vs-committed) → **▸ NOW: the three-gate v1-deletion bar (dag/gunbc/v1_deletion_plan.dag — emitter fixed point · honest frontier · ledger green)** → seed-honesty (DDC — see the prereq-drift flag on 5-collapse-v1) → **TERMINAL: `src/v1` deleted**"), section_group( label: "", nodes: [ - authored_wi(id: "5-regen-cutover", done: false, content: "**regen-cutover cadence** — absorb latent emitter fixes into the committed seed (#6099 merged with the `machine_width` emit test still ignored: two-generation regen means every emitter improvement is invisible until a cutover). Each cutover un-ignores its witnesses; a stale seed hides emitter regressions. RECEIPT (2026-07-05, local, #6253 — measured on a tree with the `get` sites resolvable; numbers independent of which #6241-gap fix lands, #6255 is the operator-chosen one): regen write-mode completes and materializes the latent backlog — 40 generated files / ~4.3k lines of drift since their last per-file writes — but the fresh crate is cargo-RED: 1667 rustc errors (E0282/E0308/E0425/E0614/E0631; dominant class = #6243's deref-boxing + alias-brand C8 tail). Cutover #1 is BLOCKED on emitter restoration to fresh-emit cargo-green; until it lands, `regen --verify` is red on that drift by construction and every emitter fix stays latent (the broken cutover was measured and NOT committed). UPDATE (2026-07-05 PM): root-caused and largely landed — 1482/1667 (E0308+E0614+E0631) trace to ONE `field_access_field_is_boxed` predicate bug (`is_recursive_type_by_name` fires for types already in `shared_types`, sending Node fields down the deref path), fixed in #6243 (merged), with #6266 as byte-identical template hygiene; the 139 E0425s are the alias-brand/use-line import class (one root, two labels), also carried by #6243. Cutover #1 now waits on: the post-#6243 fresh-emit re-measure receipt (an earlier 1482→0 receipt was measured under a since-retracted fix and must be re-earned) · #6270's `04_method.dag` backfill ✓ merged (7 hand-only #6261 registry rows in the GENERATED seed would otherwise be silently wiped by the regen) · a defensive committed-vs-fresh sweep over the remaining GENERATED files for dark-week hand edits.", intricacy: IntricacyMedium, volume: VolumeMedium, repo: "gunbc"), - authored(id: "5-real-fixpoint", done: false, content: "**real fixed point** — `content_hash` stage1==stage2 over the FULL seed. LANDED (#6218): `source_text_code_unit_digest` host-grounded on `atom_identity_hash`, and the `SelfHostRealizedComparisonGate` byte-fold widened from the 2-file roster to all 92 GENERATED files via the regen manifest (self-updating roster; the gate's INTERIM disposition deleted). REMAINING: the Node-level comparison — emitted compiler Node vs emitted bytes (`generate_stage_candidate_from_ingest` has zero consumers today) — dissolve the `bootstrap.dag` placeholder hashes, and widen the provenance witness off its 1-file roster. This milestone gates the bulk cutover-delete, seed-honesty, and the shelved TS self-host."), - authored(id: "5-dissolve-patches", done: false, content: "**drain the HAND_MAINTAINED queue** (7 files + `module_path_index`, ~22.3k LOC; three lens projections drained ✓ #6158/#6211/#6212 · last `patch_*` dead in-tree ✓ · `phase_profile.rs` added 2026-07-04, dissolution trigger `realization_measurement_loop` Phase 0; the `dag_collect` pair is GENERATED again per #6239, not a HAND drain target — its `std.content_hash` grounding stays tracked by the typed dissolve-on rows in the `.dag` and DESIGN's §3 convergence thread) — remaining dissolution order: `main.rs` flip-back (attempted #6226, self-reverted — the emitter lost Ci-subcommand/`extract_module_path` emission in #6053's dag_collect split; restore the emit gaps first) → `coproduct_reflection` (de-fork-coupled) → `v1_interpreter` pure-eval emit (kernel D [plan](docs/plans/interpreter-kernel-d.md); model+witness landed #6229, phase ModelAndWitnessOnly, blocked on emit_host transport wiring) → `cli_run.rs` (largest, ~12.1k LOC — grew as the absorption point for the drained projections' pure folds per #6211/#6212/#6217; #6046 hard-gates net-new logic INTO it). Host-physics files (`recorded_fixture` · `resolved_graph_cache`) are terminal-kernel pins, not dissolution targets."), - authored_wi(id: "5-emit-on-demand", done: false, content: "**emit-on-demand execution — prove the artifact path end-to-end** *(operator, 2026-07-07: build this and make sure it actually works, alongside self-hosting)* — the execution model is emit → build → run with content-addressed reuse, never long-lived interpretation: emit a v2 closure to Rust via the seed, build it (sccache-warm), run native, `Share` the artifact by content-hash. First customer: the S1 parse census — `02_parse` + closure emitted once, the census runs native (compiled parser measured LINEAR 1.1ms→13.9ms across 43→6173 words, 2026-07-07 forensics, vs interpreted class-broken pre-fix: 1956w DNF at 900s / 4.35GB RSS — root cause the `length` builtin's O(n) clone-to-count × per-attempt calls = O(n²), interpreter fix in the forensics lane). ACCEPT: (a) same-input interpreted==native agreement witness on the first customer; (b) content-hash reuse receipt — second run pays zero compile; (c) the interpreter's surviving roles named and bounded (bootstrap receipts · compile-time eval), each carrying dissolution trigger = the self-hosting cutover; a NEW long-running interpreted workload is a review reject — route it through emit-on-demand. Interpreter fixes stay scoped to keeping the bootstrap usable, never investment (no bytecode VM, no JIT — closed static substrate ⇒ the AOT artifact dominates; DESIGN §4).", intricacy: IntricacyMedium, volume: VolumeMedium, repo: "gunbc"), + authored(id: "5-regen-cutover", done: true, content: "**regen-cutover cadence — closed by construction (audit 2026-07-23)**: `regen --verify` is a required CI step, green on every main push; #6957/#6958 moved rustfmt normalization to production emit, so all 98 generated files are byte-identical fresh-vs-committed and the two-generation latency this cadence existed to absorb is unwritable. The July-5 cargo-RED/cutover-blocked receipts died with #6243. Forward fixed-point work lives in the v1-deletion plan (^regen_fixed_point_receipt)."), + superseded(id: "5-real-fixpoint", by: "dag/gunbc/v1_deletion_plan.dag ^emitter_fixed_point + ^regen_fixed_point_receipt", content: "**real fixed point** — re-based to the behavioral 2-generation bar (byte-fixpoint an explicit non-goal, #6922/#7092); the landed byte-fold half (#6218) lives on as the required ci_regen gate. Residual the successor does not carry: generate_stage_candidate_from_ingest has zero consumers (candidate_generation.dag)."), + authored(id: "5-dissolve-patches", done: false, content: "**drain the HAND_MAINTAINED queue** — re-measured 2026-07-23: 25 files + `module_path_index` (regrown from 7 by pre_push, memory_governor, census_exclude_derive, std_lens_verdict, 3 usv_pilot files, and 10 v2_compiler_* native-routing shims — each landed with its own dissolution trigger; drain as the triggers fire). The cli_run.rs drain has its own plan: [cli_run.rs hollowing, #7084](docs/plans/cli-run-hollowing-plan.md)."), + superseded(id: "5-emit-on-demand", by: "witness-realization lane — v1_deletion_plan ^witness_realization_kernel / ^witness_family_fanout · docs/plans/witness-realization-plan.md", content: "**emit-on-demand execution** — landed there by execution: kernel #6879, family fanout #6893/#6894/#6895/#6917, native path 9/9 families green + falsifier wet-cadence enrollment #6990, one-build-grain #7042, artifact store #6738; carrier src/v2/std/emit_on_demand.dag. The S1-parse-census first-customer framing is obsolete."), derivable(id: "5-dual-rep-lens", prs: [6104], title: "**no-dual-representation-test lens rebuilt pure-v2**", description: "— lens verdict moves off v1 Rust, the lens-E retirement pattern continued (landed #6104)"), authored(id: "5-defork", done: false, content: "**de-fork dag ↔ v2 grounding cluster** (one std authority — the fixed point must be well-defined over ONE algebra): `algebra` first (LIVE fail-open, 75 floor entries) → effects/float/integer/logic → `nat` LAST. Operator rulings stand: coproduct = structural authority; grounded-realization wins. The cost of not de-forking is no longer theoretical: the `extdeps.shell` dag↔v2 fork silently shadowed `shell.Which` in the two-root module index and kept main red from #6097 until the de-fork hotfix. [brief](docs/plans/dag-v2-defork-audit.md)"), authored(id: "5-root-b", done: false, content: "**Root B repoints** — def-unification (coproduct authority + aliases) → repoints (algebra/nat/integer/float/logic/effects/verification) → 🟡-marker dissolution (keystone #5552 merged)"), authored(id: "5-v1coupled", done: false, content: "v1-coupled `coercion`/`node` renames — deferred to v1-delete"), authored_wi(id: "5-test-migration", done: false, content: "**test-migration lane** — live debt per the `v2.lens.test_migration_debt` shrink-only ratchet: 73 v1 test modules / 731 `#[test]` fns / ~23k LOC with no exact-stem floor witness (baselines 77/912/28546 set 2026-07-02; `pipeline.rs` alone is 417 fns, the dominant unit); the delete-guard blocks removing a v1 test module without its floor witness (hard gate per module, bulk-delete forbidden). **Scrutinize before migrating (operator, 2026-07-05): tests are not inherently valuable — triage each module first (migrate · delete-as-redundant · delete-as-low-value); the guard currently requires an exact-stem witness for ANY delete, so the lane's first deliverable is a typed retirement path through the guard, never a bypass.** Parallelizable now; gates the terminal collapse per module. NOTE: migrated witnesses run on the local discovery path — CI enrollment is opt-in (#6232) until affected-set selection lands. UPDATE (2026-07-05): the typed retirement path LANDED (#6261 — `RetirementDisposition` model, guard union, import-bound `covered_by`), and the first drain tranche merged the same day (#6268/#6270/#6271/#6272: complexity-bounds, transport_emit, scrambled_name, self_gen8 clusters; baselines ratcheted 912→881 fns / 28546→28054 LOC, tightening further at each rebase). Triage finding so far: the delete mass concentrates in the `pipeline.rs`/`parse.rs` batteries (~64% of debt fns); the small-module tail mostly guards real v1 behavior whose dag/std concept exists but is UNWITNESSED — genuine migration work, not deadweight.", intricacy: IntricacyMedium, volume: VolumeLarge, repo: "gunbc"), - authored(id: "5-emitted-crate-partition", done: false, content: "**emitted crate partition — derive the crate layout, don't hand-draw it** — `stage0_crate_plan()` hand-assigns ~49 modules to `v1_stage0_core` / 7 to `v1_stage0_emit_core` with **zero** references to the module authority (`frontier.dag`): #6677 made the frontier the single authority for module *registration*, but crate *membership* is still a hand ledger — the last uncovered fork in crate organization (§3: a private ledger with no dissolution path). The Rust realization's workflow-layer half of a target-agnostic contract (the shared `CompilationUnit` + `partition_fold` home is the language-consolidation lane's; C is the second realization). Status: design, interface-locked 2026-07-16; implementation owner TBD. [design](docs/plans/emitted-crate-partition-design.md)"), - authored(id: "5-cargo-green-continuous", done: false, content: "**make cargo-green continuous (or cheap)** — `route_a_emit_fresh_cargo_green_test` is ignored (~3–5min); an emitter regression that keeps bytes stable per the old seed but breaks a fresh build surfaces late. Decide: fold into `RegenVerifyGate` (doubles its cost) or a scheduled receipt. (This exact failure mode materialized 2026-07-05: fresh emit = 1667 rustc errors, accumulated invisibly while the byte wall was dark — see the regen-cutover receipt.)"), + authored(id: "5-emitted-crate-partition", done: false, content: "**emitted crate partition** — derived partition LANDED #6747: v2.workflow.rust_crate_partition grounds on the self-host frontier roster → stage0_crate_partition_generated.dag → consumed by src/v1/stage0_crates.dag, proven by build + regen_verify. Remaining open: the rows are a HandExplicit interim (dissolve-on: PolicyPartition) and interface Node grounding is deferred (stage0_module_dag_interface_grounding debt note). [design](docs/plans/emitted-crate-partition-design.md)"), + authored(id: "5-cargo-green-continuous", done: true, content: "**make cargo-green continuous (or cheap)** — resolved by construction, neither named option: post-#6958 the fresh emit is byte-identical to the committed seed (98/98, production-side normalization), the required ci_regen step proves that identity on every main push, and CI builds the committed seed every run — so fresh-emit cargo-green is continuous by composition; the named failure mode (bytes stable per the old seed, fresh build broken) is unwritable. Residual cleanup: route_a_emit_fresh_cargo_green_test still #[ignore] — keep-as-local or delete."), authored(id: "5-seed-honesty", done: false, content: "**seed-honesty discharge** (Diverse Double-Compiling) — modeled in `bootstrap.dag` (`SeedHonestyDischarge`), no execution exists; worse, the modeled witness is fail-open by construction (its evidence argument is the same atom it checks against — Holds trivially, no red case constructible) until Stage 3's executing consumer lands. Needs a reproducible artifact to double-compile. Design proposal (second-compiler candidate `ddc_reference_compiler` + computed fixed-point digest, reusing `self_host.dag`'s `canonical_emitted_bytes_digest`; FLAGs A–D open for operator sign-off): [seed-honesty discharge design](docs/plans/seed-honesty-discharge-design.md)"), - authored(id: "5-collapse-v1", done: false, content: "**TERMINAL — collapse `src/v1`**: one atomic regen cutover-delete of the 92 GENERATED files (~117k of stage0's ~137k LOC) + per-module test deletes as migration lands + pin the terminal kernel. Requires: HAND queue empty · real fixed point · test-migration green · seed-honesty."), + superseded(id: "5-collapse-v1", by: "dag/gunbc/v1_deletion_plan.dag ^v1_quarantine + ^v1_delete (three-gate bar, #6922/#7092)", content: "**TERMINAL — collapse src/v1** — the deletion bar lives in the three-gate plan (GateEmitterFixedPoint · GateHonestFrontier · GateLedgerGreen) with frontier.dag (#7058) carrying per-module dispositions. PREREQ DRIFT ruled 2026-07-23 (prereq_drift_ruling_2026_07_23 in v1_deletion_plan.dag, PR #7110): the three gates are the interpreter-deletion bar and correctly omit all three; the terminal claims restore them as GateDeletion bricks — hand_queue_drain before v1_quarantine, test_migration + seed_honesty_decision before v1_delete."), ], edges: [ RoadmapEdge { child: nid(s: "5-real-fixpoint"), parent: nid(s: "5-regen-cutover") }, @@ -161,11 +165,11 @@ fn section_2() -> RoadmapSection { label: "Now — correctness of the current posture", nodes: [ owned(rn: authored_wi(id: "2-cd-transport", done: true, content: "**fix the CD transport premise — a deploy needs a target-host proof** — `deploy_dashboard_srv1` is a *srv1 effect*, but job placement is not an srv1 *proof*: `LocalShell` with principal `runner` assumed the runner is ON srv1 (#6093), while `[self-hosted, linux, arm64]` can land on srv2 (and during the Ubicloud window it was a rented VM). A `LocalShell` deploy is valid ONLY when the runner identity proves it is already on srv1 — either pin the job to an srv1-specific trusted runner label, or make the effect `SshShell`-over-tailnet with an explicit srv1 target + typed credential (#6066 Phase 2). Until then every main push gambles the deploy host.", intricacy: IntricacyHigh, volume: VolumeSmall, repo: "gunbc"), owner: "dispatched 2026-07-01 · adhoc-75790c4c-4e0"), - with_plan(rn: authored_wi(id: "2-dispatch-actuator", done: false, content: "**roadmap dispatch actuator — dispatch + maintain Claude Code sessions from the srv1 roadmap (simple MVP)** *(operator directive, 2026-07-03 — un-shelves the actuator slice of §4 \"roadmap-as-spawner\")* — a Dispatch button per READY item that spawns a real `claude` session on srv1 (git worktree + detached tmux + brief seeded from `dispatch_brief_template`), plus GET /sessions / Stop. Reuses `roadmap_spawner` frontier, `session_lease` gating, the emitted-Node-server lane (`node_http_server_emit` grows the dynamic-route/POST handler lane its dissolution trigger already names). Displaced cost: every dispatch today is the operator hand-writing a brief and hand-spawning a session. **Accept (T4):** press Dispatch on one real READY item → a live claude session in a worktree on srv1 working the item, visible in the panel, torn down by Stop; independent read-back = `tmux ls` + transcript file, never our own write; RED: dispatching a non-ready node or a node with a live lease is a typed refusal. Milestones M1–M4 in the plan.", intricacy: IntricacyHigh, volume: VolumeMedium, repo: "gunbc"), path: "docs/plans/dispatch-maintain-cc.md"), + with_plan(rn: authored_wi(id: "2-dispatch-actuator", done: false, content: "**roadmap dispatch actuator** — machinery LANDED and live: first end-to-end dispatch on srv1 by execution (#7096 go-live receipt; belt A #6942 · belt B gunbc serve #6940 · single dispatch authority #6914 · spawn/observe/reap #6836; Dispatch button reads the belt-B status contract; claude preflight typed refusals; independent read-back = tmux ls). REMAINING vs the T4 accept: no Stop verb and no GET /sessions surface (roadmap_serve routes carry only POST /dispatch + statics), and re-dispatch after Stop is one-shot-broken (filed as ts-dispatch-redispatch, sized ready row).", intricacy: IntricacyHigh, volume: VolumeMedium, repo: "gunbc"), path: "docs/plans/dispatch-maintain-cc.md"), authored_wi(id: "2-admission-model", done: false, content: "**workload-class admission model** *(operator directive, 2026-07-01: 1 core → 3 GiB + swap)* — runners are capacity surfaces, not concurrency proof. Define CI workload classes (`floor_light` · `rust_heavy` · `deploy` · `session`) with measured RAM/swap/pids/CPU-token demand; **admitted concurrency per host derives from HostSupply × WorkloadClassDemand, never from runner-slot count**. Initial 128c/125GiB policy: ~42 build tokens per host (≈1 core : 3 GiB, the `ubicloud-standard-16-arm` shape generalized), with intentionally-stranded cores reserved for sessions and low-memory work — stranded is not wasted. Measured anchors: ci ~11GiB · rust_tests ~37GiB peaks vs the old 8G slot caps. **Accept:** admitted concurrency for srv1/srv2 derives by execution from HostSupply × WorkloadClassDemand (witnessed, not hand-set to match), and a proposed allocation whose Σ exceeds supply is REFUSED with a typed verdict — perturb: inflate one class's measured demand and admission shrinks.", intricacy: IntricacyHigh, volume: VolumeMedium, repo: "gunbc"), - authored(id: "2-cap-deconflation", done: false, content: "**cap/admission de-conflation** — three different facts, one knob today: per-slot *containment* (`memory.high` pressure target · `memory.max` hard ceiling · `swap.max` survival ceiling — ceilings, not reservations) vs host *admission* (how many heavy jobs may run) vs in-job *build width* (`CTRL_JOBSERVER_TOKENS` / cargo jobs). The 8GiB fleet slot contract, the 24GiB stopgap, the 37GiB rust_tests peak, and the 42-token host policy are different facts; splitting them is what makes the width fold and budget tree honest (spawn_width already derives from live `memory.max` by construction — the #6107-deferred item was only this split)."), + authored(id: "2-cap-deconflation", done: false, content: "**cap/admission de-conflation** — re-based 2026-07-23: the three facts now live in three mechanisms — per-slot containment = cgroup caps via converge (#7009/#7000) · host admission = fleet_host_budget conservation (host_allocation_conserves) · build width = the runtime AIMD memory governor (2026-07-12 adaptive-width ruling, which retired the width folds and per-shard byte predictions the original framing assumed). Remaining ask: a receipt that the three mechanisms cover the original knobs with no conflated survivor, or re-home the residue."), authored_pp(id: "2-merge-admission", done: false, content: "**merge-admission gate: close the HELD state** — wired (#5974/#6080) but the freshness block is HELD pending a real green-on-main receipt, and the #6080→#6101 accidental re-apply/re-revert needs a clean landing. Evidence it is needed: stale-base merges landed BOTH `.gitignore` drift (healed #6110/#6111) AND the `extdeps.shell` collision that kept main red — green-on-branch is not green-on-main.", carriers: [ptr(label: "decision record", path: "docs/plans/ci-merge-freshness.md")]), - authored_wi(id: "2-stateless-frontend", done: false, content: "**stateless frontend MVP on fabric** *(operator directive, 2026-07-01)* — the first **non-CI, product-shaped consumer** of `RunShape → Allocation → Receipt`: point a domain at an IP and serve the process as minimally as possible. Model `SiteArtifact` (digest · media_root · build_recipe) + `WebServiceShape` (cpu/ram/port/stateless/health_path) + `DomainRoute` + `ServiceAllocation`. MVP is intentionally single-site/single-allocation: DNS may be manual (`DnsExternalManual` recorded, not actuated), storage is immutable/content-addressed, compute is a tiny stateless HTTP process, and the receipt proves `/healthz` plus **served artifact digest** — green only when an independent read proves domain → endpoint → process → digest. NO autoscale, NO dynamic user routing, NO DNS/cert automation. Two milestones: **(A)** StaticSite deploy receipt on the current srv1 path — can start now; **(B)** fabric `SiteLease` on the same allocation model as CI — waits for the control-plane read-back. Exists to prove storage+compute+route can be allocated, read back, and retracted through the same apply/receipt pipe as fleet config — a safer fabric consumer than oversubscribed CI (route/supervision/artifact risk, not memory/OOM risk).", intricacy: IntricacyHigh, volume: VolumeMedium, repo: "gunbc"), + authored_wi(id: "2-stateless-frontend", done: false, content: "**stateless frontend MVP on fabric** — milestone (A) LANDED: roadmap static site served on srv1 (#6128) + healthz REST GET readiness edge (#6753) + bounded read-back (#6769) + roadmap_site_healthz_validate; live_deploy apply/retract on the membership spine (#6814/#6940/#7011). REMAINING: milestone (B) fabric SiteLease on the same allocation model as CI (waits on the control-plane read-back); the public-domain discharge (gunb.ai Pages cutover) is assigned to the site-subsumption lane and has NOT merged yet.", intricacy: IntricacyHigh, volume: VolumeMedium, repo: "gunbc"), ], edges: [ RoadmapEdge { child: nid(s: "2-stateless-frontend"), parent: nid(s: "2-cd-transport") }, @@ -175,8 +179,8 @@ fn section_2() -> RoadmapSection { section_group( label: "Floor throughput — reduce work, then schedule it (26m → <1min on a typical PR)", nodes: [ - authored(id: "2-compile-clean-serial", done: false, content: "**kill the serial compile-clean wall** *(the measured dominant cost — 2026-07-01 receipts from the first Ubicloud main run and its self-hosted twin)* — batch-1 `dag_compile_clean_gate` is ONE node in ONE resolve-group: ~47 of the ~50min step, immune to `spawn_width` (width=9 was live and only parallelizes the ~4min batch-2 tail; same wall on both runner types — the bottleneck is structural, not the host). Levers in leverage order: (a) affected-set-scope the compile-clean to the changed node-closure; (b) cross-run resolve memoization (the per-module resolve cache is within-process only — nothing persists across runs); (c) shard the gate per-module so the width budget finally applies to the dominant node. NOTE the 2026-06-24 profile (26m whole floor) and this receipt (~47min batch-1 alone) disagree — re-profile is part of the §3 audit."), - authored(id: "1-wallclock-measured", done: false, content: "**the floor is a full recompute every run** — profiled 26m (2026-06-24): ~518s resolves all 870 witnesses cold, a second ~275s discovery pass, ~360s effect-bound gates, ~134s seed compile; on a one-file PR ~99% of the resolve recomputes witnesses whose inputs did not change. **Target: <1min.** The lever is resolve-phase incrementality, NOT cross-run caching — CI is cold-dominated (the exe-hash re-colds on every code change)."), + authored(id: "2-compile-clean-serial", done: false, content: "**kill the serial compile-clean wall** — re-based 2026-07-23: lever (a) LANDED — per-PR import-closure scoping via tools.dag_compile_clean_scope (2026-07-16) + loader-closure de-fork #6950; the cost picture moved under it (#7001 memory-thrash-not-compute · #6808 sigs-env 2461s→65s, 37.6× · #6999/#7030 namespace-walk fixes; width regime = adaptive governor). Remaining: lever (c) — shard A's compose proof landed but shards were never enrolled in the floor plan (2-compile-clean-shard-b, re-price first); whole-tree baseline runs still pay the serial wall on the falsifier/cold cadence."), + authored(id: "1-wallclock-measured", done: false, content: "**floor wall-clock on a scoped PR — target <1min** — the original headline (the floor is a full recompute every run) is discharged: witness-level affected-set selection is LIVE in CI (discovery flip, operator acceptance 2026-07-09; fail-closed selection + falsifier cold control) plus compile-clean closure scoping. The 2026-06-24 profile numbers predate #6848/#6808/#6999 and are void. Target <1min still unmet on cold/whole-tree paths — remaining lever is resolve-phase incrementality, re-based on current receipts."), authored_doc(id: "1-affected-set-defork", done: false, content: "**affected-set de-fork — `v2.lens.affected_set` as single authority** — witness-level run/skip live (#6061, v1 `force_run_all` hack retired); remaining: precompute-skip wired to the same one `.dag` query, the Rust parallel (`NodeFrontierSeeds`) deleted (N→1), and a wall-clock+RSS receipt on a scoped diff.", path: "docs/plans/affected-set-precompute-pruning.md"), derivable_doc(id: "2-provenance-ingest", prs: [6105], title: "**provenance ingest live at floor runtime**", description: "— successor lane: resolver S2a + skip-before-resolve remaining fix (PR #6105 closed 2026-07-02 measured work-neutral); node-closure grounding for `v2.lens.affected_set` to be live during the floor pass; gates node-level pruning + the Rust-bridge deletion", path: "docs/plans/affected-set-precompute-pruning.md"), derivable_doc(id: "2-host-scaffold-classifier-defork", prs: [6224, 6479], title: "**host-scaffold witness classifier de-fork — DONE**", description: "— the claim_executor Rust text classifier (`witness_test_fn_uses_live_host_scan`) and the interim `floor:host_scaffold` marker are dissolved into the substrate-declared `LiveTreeDisposition` row (#6479). Placement correction vs this row's original wording: the disposition lives as a `data live_tree_disposition` row in the WITNESS ENTRY FILE (`v2.std.live_tree`), not as a field on `TestClaim` rows — a claim row asserting a foreign entry's liveness would be a second carrier of the same fact (§3 dual representation); the entry's own row is the single authority. Undeclared = ReadsLiveTree = never predict-skip (fail-closed); the nightly affected-set falsifier is the enforcement for lying declarations; call-reachability grade re-derivation is the later lane", path: "docs/plans/affected-set-precompute-pruning.md"), @@ -205,12 +209,12 @@ fn section_2() -> RoadmapSection { label: "Control plane — the #6096 re-land, done right (G2/G3)", nodes: [ authored(id: "1-g2-runner", done: false, content: "**G2 runner deployment derived from `fleet_intent`** — runners/host + registration from the modeled envelope; the gunbc-EMITTED converge shell is the host-apply carrier (operator-set). The umbrella for the re-land below. **Accept:** a runner-count/allocation change on srv1/srv2 lands by editing the modeled envelope only — registration + slots + caps converge from the model, independent read-back proves the live units match, and a hand-registered rogue runner is detected as drift (RED), never absorbed."), - authored_wi(id: "2-converge-reland", done: false, content: "**closed-loop converge re-land** — the signed design: base snapshot → edit → **three-way diff** → gated plan → apply → **independent read-back** → commit/retract; **hostname self-selection** (the committed script runs all three hosts' rows unconditionally); **sound host admission** (own node below); runner-width **INCREASE provisioning** (today an echo-to-stderr stub). The three-way-diff carrier does not exist yet in `dag/gunbc/` — and it is a **fold instance, not a bespoke differ** (own node below carries the construction steer; this node's dispatch brief inherits it). **First acceptance case (deliberately narrow, operator-set):** change one srv2 runner-slot memory/swap value — read current → refuse if drifted → apply → read back → commit new base; re-apply is a noop; retract works. **Full acceptance (T4 — operator, 2026-07-02; [12-step checklist](docs/plans/fleet-acceptance-criteria.md)): reconfigure srv1/srv2 to a NEW runner allocation from the model alone** — edit desired (runner width + per-slot memory/swap caps, both hosts) → plan shows exactly the delta → apply per-host → independent read-back proves the new effective values (`systemctl show`, never our own write echoed back) → receipts commit as the new base; a subsequent hand-edit on either host reds the next converge; retract returns both hosts to the prior allocation; the values survive `daemon-reload` and a freshly spawned runner unit inherits them. That, not the narrow first case, is this node's done bar. No Ubicloud inside this PR: just make srv1/srv2 mutable safely. This is the real blocker — until it lands, every fabric model is paper.", intricacy: IntricacyHigh, volume: VolumeLarge, repo: "gunbc"), + authored_wi(id: "2-converge-reland", done: false, content: "**closed-loop converge — T4 acceptance on the spine** — re-based 2026-07-23: the three-way-diff carrier EXISTS (host_converge_delta.dag + srv2 ConvergeKnob fixture witness); converge thin-run landed (#6572/#6585/#6598, re-verified 2026-07-20); per-slot MemoryMax convergence generalized multi-unit (#7009) and srv3 caps via host-standup converge (#7000); apply/teardown poles unified on the membership_reconcile spine (#6814) — deploy = one fleet reconcile spine (operator). REMAINING (this node's bar, unchanged): the full T4 accept — reconfigure srv1/srv2 to a NEW runner allocation from the model alone, plan shows exactly the delta, independent read-back (systemctl show, never our own write echoed back), hand-edit reds the next converge, retract restores, values survive daemon-reload ([12-step checklist](docs/plans/fleet-acceptance-criteria.md)); the live read seam is still ReadAbsent (fleet_show_effective_read) — bind ReadObserved at the apply increment.", intricacy: IntricacyHigh, volume: VolumeLarge, repo: "gunbc"), authored(id: "2-host-admission", done: false, content: "**sound host admission — Σ-accounting with two modes** — post-patch values feed Σ-accounting over RAM, swap, pids, and CPU tokens. **Guaranteed mode**: Σ(memory_max) ≤ RAM budget ∧ Σ(swap_max) ≤ swap budget (safe, conservative). **Burst mode** (the CI target — we trust our jobs): admission from measured class demand + margin, caps as containment ceilings not reservations, and the receipt window must prove admitted×ram_margin+headroom ≤ host_ram, admitted×swap_margin+reserve ≤ host_swap, and oom_kill/swap_fail counters did NOT increase. A plan that passes only by assuming every slot simultaneously consumes its burst ceiling is rejected or explicitly marked Guaranteed-mode. Replaces the too-weak single-slot swap compare that helped sink #6096. **Accept ([checklist](docs/plans/fleet-acceptance-criteria.md)):** admission computes from POST-PATCH desired values (feeding base values instead is a RED); an overcommitted Guaranteed plan fails Σ-accounting by execution; a Burst plan proves its margins; live receipt = one real srv2 window with pre/post `memory.events` showing oom_kill and swap-fail counters did NOT increase."), owned(rn: authored_wi(id: "2-live-read-runner-memory", done: true, content: "**live read, first slice: one runner unit's memory knobs** — read `MemoryMax`/`MemorySwapMax`/`MemoryHigh` for ONE live actions-runner instance and ground the result into the ConvergeTarget semantics (no string flattening). Non-goals: no patch/apply engine, no runner-count reconciliation, no timer. RED: a fixture read that differs from base refuses convergence (`NotConverged`); green receipt: one real srv2 unit read grounded into the model. Stop-and-return if systemctl read output cannot be represented typed.", intricacy: IntricacyHigh, volume: VolumeSmall, repo: "gunbc"), owner: "dispatched 2026-07-01 · adhoc-1e9d7c44-bcc"), authored(id: "2-live-read-seam", done: false, content: "**live host read seam (full)** — `fleet_show_effective_read` replaces `ReadAbsent` for cgroup caps, runner count, jobserver tokens, swap, and pinned-tree status; synthetic-read witnesses are NOT enough for periodic actuation (the reconciler substrate exists — the live host read is the load-bearing missing piece). The effective base for converge is `host_converge`'s `ConvergeKnob` rows, not `fleet_intent` (physical inventory). Grows knob-by-knob from the first slice above. **Accept (T3/T4 read-side; [checklist](docs/plans/fleet-acceptance-criteria.md)):** live typed reads on BOTH srv1+srv2 covering the runner units (`actions-runner@-*.service`), `MemoryMax`/`MemoryHigh`/`MemorySwapMax`/`TasksMax`/`CPUWeight`, runner count, and the jobserver token value; fixture REDs (absent property → typed Absent · `infinity` where bytes expected → drift · wrong bytes → drift); full-host receipts list EVERY runner unit's effective knobs; NO mutation anywhere in this node; the converge precondition consumes these reads. The first slice does not close this node."), owned(rn: authored_wi(id: "2-privilege-model", done: true, content: "**privilege model for host mutation** — converge writes `/etc/systemd/system/*.d` and runs `systemctl set-property` (root), but #6096's service ran as the operator user with `|| true` swallowing EPERM; extend `DeployAccess`/`host_effect` so an unprivileged apply is a **typed refusal BEFORE mutation**, never a swallowed failure. RED: unprivileged mutation emits no shell / no `host_effect_apply`; green: the privileged modeled path applies in a fixture.", intricacy: IntricacyHigh, volume: VolumeSmall, repo: "gunbc"), owner: "dispatched 2026-07-01 · adhoc-3b95241c-d5d"), - authored_wi(id: "2-keyed-delta-fold", done: false, content: "**three-way diff = the core fold with a lattice codomain — not a new differ** *(operator, 2026-07-01: \"is there something inherent to fold/homomorphism that would get us this for free? I'm worried we are reinventing our core mechanism\" — confirmed; this node is the construction steer)* — diff is a keyed fold over aligned rows into an algebraic codomain with identity = `Unchanged`: unchanged rows contribute nothing **by the monoid law**, never by filtering — that is the \"for free\". Structural equality is the degenerate consumer of the same walk (`v2.std.exact_structural_equality_zip_fold` — canonicalize each side, one top-level `==`: an equality verdict is a diff with the hunks discarded; note its internals are canonicalize-then-compare, not a lockstep zip, so the diff fold is a sibling reading, not a call into it); a hunk is the located, typed mismatch coercion already emits (`find_witness` Diagnostics, subject-level locus) collected as data instead of refusing on the first. Three-way is the same fold into a join-semilattice — the `DescentEvidence`/`BoundedLattice` precedent (`dag/std/termination.dag`) with its safety consciously INVERTED: bottom here is the BENIGN `Unchanged`, so the codomain must carry NO Unknown element (an Unknown at bottom would join-fold unreadable state to \"no change\" — a §5 fail-open; unreadable state is refused upstream at the typed-read wall, never folded) — and `Conflict` = the join of two incomparable changes, so \"no mutation on conflict\" is **structural** (a plan that reads `Conflict` has no apply arm), not a runtime guard. The inverse laws are the free RED controls (DESIGN §5): `diff(A,A) = identity` · `apply(diff(A,B), A) = B` · retract = the inverse patch — a groupoid, NOT a total `Group`: apply is partial (refuses off-base) and `Conflict` has no inverse; deriving a total apply from Group inhabitance would silently compose through drift. Alignment is free HERE because converge knobs are keyed (a keyed zip is total); general insert/delete tree alignment is a search, explicitly NOT this scope. §3: the change vocabulary EXISTS — `v2.std.change` (`ChangeKind` NodeChanged/NodeAdded/NodeRemoved + projection/artifact arms · `ChangeSet`, already feeding the affected-set lens); attach there or de-fork consciously, never mint a parallel Hunk/Patch — and the algebra anchor picks ONE std authority consciously (`algebra` is pillar-1's FIRST de-fork target, LIVE fail-open; standing ruling: coproduct = structural authority, grounded-realization wins). Layering: the generic keyed-delta/three-way fold is a `std` carrier; `gunbc.host_converge` supplies ONLY the leaf algebra — `ConvergeTarget` keying + per-target normalization/equality across all SIX variants (`SliceProperty` splits apply-value from expected-effective · `PerSlotMemoryCap` byte-normalizes · `RunnerWidth` · `JobserverTokens` · `VerifyOnlyCap` has no apply value at all · `GunbcPinnedTree` converges on pin-coherence, not value equality — one string-equality flattens ALL of that) + apply/retract semantics; live read/apply stays workflow-layer. **Accept (T2 — wired; [checklist](docs/plans/fleet-acceptance-criteria.md)):** (a) law witnesses green with RED perturbs — identity · apply∘diff · inverse-retract · key-reorder invariance · incomparables join to `Conflict`; (b) on real srv2 `ConvergeKnob` fixture rows (base/observed/desired) the plan lists EXACTLY the changed knobs — unchanged knobs absent by the identity law, a drifted knob folds to `Conflict` and no apply arm is reachable from it; (c) `host_converge` computes a REAL converge patch through this carrier — proof by consumption, not grep: remove the carrier and the re-land witness fails to resolve. T4 arrives only via the converge re-land. NOT accepted by: the algebra existing, typechecking, or a hand-rolled compare that happens to agree.", intricacy: IntricacyHigh, volume: VolumeSmall, repo: "gunbc"), + authored_wi(id: "2-keyed-delta-fold", done: false, content: "**three-way diff = the core fold with a lattice codomain** — accepts (a)+(b) MET by execution: generic keyed fold attached to std.change (#6129, keyed_two_way_diff in dag/std/change.dag; 30 law witnesses incl. identity/reorder/conflict-join) and srv2 ConvergeKnob fixture rows + leaf algebra (host_converge_delta.dag). REMAINING: accept (c) proof-by-consumption — host_converge does not import the carrier (only the witness consumes it); live consumption instead arrived via membership_reconcile (#6814 live_deploy poles, #6820 belt R9) — either re-point (c) to the spine deliberately or wire host_converge through the carrier.", intricacy: IntricacyHigh, volume: VolumeSmall, repo: "gunbc"), authored(id: "2-periodic-actuation", done: false, content: "**periodic actuation with receipts** — a systemd timer (or ctrl thin-run) executes the emitted converge per-host under the privilege model; receipts land where a hand-edit REDS (G3's unmet promise). Until this exists the emitted shell is spec-without-execution. **Accept (T5; [checklist](docs/plans/fleet-acceptance-criteria.md)):** installed timer on BOTH hosts under the privilege model; per-run receipt (host · model hash · observed hash · applied/noop/conflict · changed knobs) lands where CI/dashboard reads it; a no-change run is a green noop; a hand-edit to a managed cap is DETECTED — auto-correct knobs restore with read-back proof, verify-only knobs (`VerifyOnlyCap` semantics) refuse with a conflict and do not mutate; RED: broken sudo → typed refusal · removed read access → `NotConverged`. A timer existing is not acceptance."), authored_wi(id: "2-runner-allocation-v0", done: false, content: "**runner allocation v0 — srv1/srv2 as StrictLease runner capacity, hand-config retired** *(the operational milestone this control plane exists for — operator, 2026-07-02)* — desired allocation declared in the model per host (runner slots + labels · per-slot `MemoryMax`/`MemoryHigh`/`MemorySwapMax`/`TasksMax` · jobserver tokens), applied by converge, proven by read-back. **Accept (T4, held alive by T5; [checklist](docs/plans/fleet-acceptance-criteria.md)):** every active runner unit on BOTH hosts matches desired effective values by independent read and a freshly started unit inherits the template drop-ins; admitted heavy concurrency derives from the admission model and GitHub cannot schedule past it (labels/slots ARE the backpressure — generic self-hosted labels cannot bypass heavy admission); receipt records host · unit count · labels · effective values · model hash; RED: a hand-edited srv2 cap reds the next converge/receipt · desired heavy concurrency above admission is rejected · wrong/missing label fails the dispatch witness · unprivileged apply refused before mutation; workload proof: one real CI run on the intended shape with no oom_kill increase and peak memory recorded as a measurement row. Not complete while ANY runner-allocation knob on srv1/srv2 requires a hand edit.", intricacy: IntricacyHigh, volume: VolumeMedium, repo: "gunbc"), authored(id: "2-service-receipt", done: false, content: "**service allocation receipt** — independent read-back for frontend services: process running, effective port, route installed, artifact digest served; retract removes route+process. Reuses `reconcile_grounded` (apply → read host back → converge only on observed evidence); failure to read route/process/artifact is `NotConverged`, never success. Generalizes the stateless-frontend MVP's receipt into the fabric's service story. **Accept (T4; [checklist](docs/plans/fleet-acceptance-criteria.md)):** one real service on srv1/srv2 applied AND retracted — read-back proves process · listening port · route · served digest == desired; re-apply is a noop; after retract, read-back proves ABSENCE; RED: right process wrong digest → `NotConverged` · route present but port dead → `NotConverged` · shell exit-0 with failed read-back → `NotConverged`."), @@ -224,13 +228,13 @@ fn section_2() -> RoadmapSection { authored_doc(id: "6-shell-intent-phase1", done: false, content: "**shell→intent Phase 1 — agnostic orchestration emit** — MERGED (#6832), operator sign-off PENDING — `While`/`BoundedPoll`/general `Retry` (N-level escalation) emit via `05_emit_orchestration` + bash grammar rows; byte goldens `orchestration_*_emit_test`; production consumer `ci_floor_peak_emit.dag`. Flip to `done: true` + `sign(operator)` on sign-off (mirrors `6-shell-slice2`).", path: "docs/plans/shell-intent-emit-realization-design.md"), authored_doc(id: "6-shell-slice2", done: false, content: "**slice 2 — converge thin-run** — implementation MERGED (#6572 keystone `ConvergePlan`+`EmitArtifactThenThinRun`+`converge_apply` · #6585 golden shrink 323→21 lines · #6598 `gunbc converge --host` CLI receiver), operator sign-off PENDING — fleet_converge steady-state interpreted in the binary as a typed plan via `apply()`; emitted bash is the fresh-standup bootstrap fragment + thin invocation lines (supersedes 'emit the whole `.github/fleet-converge.sh`'). FLAGs 2a(i)/2b/2c signed/discharged 2026-07-14 ([census](docs/plans/shell-to-dag-residual-census-and-arc-completion.md) §2); receipts re-verified by execution 2026-07-20 (`fleet_converge_emit`/`fleet_converge_apply` witnesses). Flip to `done: true` + `sign(operator)` on sign-off (mirrors `6-shell-intent-phase1`).", path: "docs/plans/shell-emission-model.md"), authored_doc(id: "2-host-effect-phases", done: false, content: "**`apply()` Phases B–F** — B `host_exec`→`apply()` (gated on srv3 OsInstalled) · C Redfish live (partially via #6097) · D converge lane = EmitArtifactThenThinRun handler (first ctrl LOC deleted) · E pull-mode self-converge (autoinstall plants the on-host agent; the push star retires) · F decom. Phase A landed (#5756).", path: "docs/plans/host-effect-orchestration.md"), - owned(rn: authored_wi(id: "2-temporal-effect-spine-a", done: false, content: "**temporal-effect-spine-a — temporal realization spine (T1 vocabulary)** *(operator 2026-07-02; not a workflow engine)* — `std.temporal_effect`: durable facts + `plan_next_step_from_prior_receipt_and_lease` (single prior+lease; list fold is consumer-side); 🟡 markers on stringly receipt labels + derived step id. RED: approval/lease/read-back gates. **Non-goals:** live mutation, DB, scheduler. **Accept (T1):** witness suite green.", intricacy: IntricacyHigh, volume: VolumeSmall, repo: "gunbc"), owner: "dispatched 2026-07-02 · zesty-bat-588"), - owned(rn: authored_wi(id: "2-os-install-deduction-a", done: false, content: "**os-install-deduction-a — preflight + KVM diagnostic vocabulary (T1)** *(operator 2026-07-02; deduction half; NOT wired to srv3_os_install_diagnostic until reconcile-a)* — `gunbc.os_install_deduction`: `fold_nbd_proxy_os_install_preflight_verdict` (NBD-proxy/on-ISO actuator scope — NoCloudNet incomplete for this path only), storage policy on payload, `TargetDiskState`, weak KVM verdicts (`KvmFirmwareIdleObserved`, `KvmSuggestsOsBooted`; `OsInstalled` reserved for router read-back). RED: remove storage flips ReadyToBoot; KVM login ≠ OsInstalled. **Non-goals:** live mutation, monitoring product, DB. **Accept (T1):** witness suite green.", intricacy: IntricacyHigh, volume: VolumeSmall, repo: "gunbc"), owner: "dispatched 2026-07-02 · zesty-bat-588"), - authored_wi(id: "2-srv3-install-reconcile-a", done: false, content: "**srv3-install-reconcile-a — dry-run reconcile entrypoint** *(queued; gated on temporal-effect-spine-a + os-install-deduction-a)* — `InstallAttemptIntent` + workflow steps as data; `srv3_os_install_reconcile` folds preflight + diagnostic + temporal spine; dry-run first. **Accept (T3):** dry-run receipt on srv1 actuator host.", intricacy: IntricacyHigh, volume: VolumeMedium, repo: "gunbc"), + owned(rn: authored_wi(id: "2-temporal-effect-spine-a", done: true, content: "**temporal-effect-spine-a — temporal realization spine (T1 vocabulary)** *(operator 2026-07-02; not a workflow engine)* — `std.temporal_effect`: durable facts + `plan_next_step_from_prior_receipt_and_lease` (single prior+lease; list fold is consumer-side); 🟡 markers on stringly receipt labels + derived step id. RED: approval/lease/read-back gates. **Non-goals:** live mutation, DB, scheduler. **Accept (T1):** witness suite green.", intricacy: IntricacyHigh, volume: VolumeSmall, repo: "gunbc"), owner: "dispatched 2026-07-02 · zesty-bat-588"), + owned(rn: authored_wi(id: "2-os-install-deduction-a", done: true, content: "**os-install-deduction-a — preflight + KVM diagnostic vocabulary (T1)** *(operator 2026-07-02; deduction half; NOT wired to srv3_os_install_diagnostic until reconcile-a)* — `gunbc.os_install_deduction`: `fold_nbd_proxy_os_install_preflight_verdict` (NBD-proxy/on-ISO actuator scope — NoCloudNet incomplete for this path only), storage policy on payload, `TargetDiskState`, weak KVM verdicts (`KvmFirmwareIdleObserved`, `KvmSuggestsOsBooted`; `OsInstalled` reserved for router read-back). RED: remove storage flips ReadyToBoot; KVM login ≠ OsInstalled. **Non-goals:** live mutation, monitoring product, DB. **Accept (T1):** witness suite green.", intricacy: IntricacyHigh, volume: VolumeSmall, repo: "gunbc"), owner: "dispatched 2026-07-02 · zesty-bat-588"), + authored_wi(id: "2-srv3-install-reconcile-a", done: true, content: "**srv3-install-reconcile-a — dry-run reconcile entrypoint** *(queued; gated on temporal-effect-spine-a + os-install-deduction-a)* — `InstallAttemptIntent` + workflow steps as data; `srv3_os_install_reconcile` folds preflight + diagnostic + temporal spine; dry-run first. **Accept (T3):** dry-run receipt on srv1 actuator host.", intricacy: IntricacyHigh, volume: VolumeMedium, repo: "gunbc"), authored_doc(id: "2-srv3-osinstalled", done: false, content: "**srv3 → OsInstalled** — finish the greenfield install over the solve-driven NBD-proxy actuator (#6097, live BMC); proves the install band end-to-end.", path: "docs/plans/srv3-webui-kvm-virtual-media.md"), - authored_wi(id: "2-resource-namespace-upsert-a", done: false, content: "**resource-namespace-upsert-a — vocabulary only** *(#6134 srv3 bringup follow-up; operator reshape 2026-07-03)* — `std.upsert_decision` (`ObservationVerdict` + `UpsertDecision

`); domain modules `gunbc.file_access`, `gunbc.session_lease`, `gunbc.install_media`. RED: foreign process on 10809=Conflict not kill; outside-namespace chmod=Refuse; drifted seeded ISO plans Remaster not Converged. Non-goal: live srv3 mutation.", intricacy: IntricacyHigh, volume: VolumeSmall, repo: "gunbc"), + authored_wi(id: "2-resource-namespace-upsert-a", done: true, content: "**resource-namespace-upsert-a — vocabulary only** *(#6134 srv3 bringup follow-up; operator reshape 2026-07-03)* — `std.upsert_decision` (`ObservationVerdict` + `UpsertDecision

`); domain modules `gunbc.file_access`, `gunbc.session_lease`, `gunbc.install_media`. RED: foreign process on 10809=Conflict not kill; outside-namespace chmod=Refuse; drifted seeded ISO plans Remaster not Converged. Non-goal: live srv3 mutation.", intricacy: IntricacyHigh, volume: VolumeSmall, repo: "gunbc"), authored_wi(id: "2-install-media-generic-layer", done: false, content: "**install-media-generic-layer — extract Ubuntu flavor from process** — split `extdeps/os/install_media.dag` generic shapes (fetch/remaster/serve verdicts) from `ubuntu_*` flavor rows; move `.gunbc-content-hash` sidecar + remaster policy to `gunbc/install_media_*`; mandatory before second OS/distro. Post-#6134.", intricacy: IntricacyHigh, volume: VolumeMedium, repo: "gunbc"), - authored_wi(id: "2-nbd-serve-held-session-lease", done: false, content: "**nbd-serve-held-session-lease** — NbdProxyServeSession intent with port/pid/cmdline/ISO/token fingerprint; classification + plan INSTANTIATE `std.upsert_decision` (`ObservationVerdict` + `UpsertDecision

`; domain facts as the P payload — do NOT mint a parallel lease vocabulary, cf. the fork-census 2026-07-03). RED: foreign 10809 no kill; stale matching session drains only. Live consumer: srv3 actuator.", intricacy: IntricacyHigh, volume: VolumeMedium, repo: "gunbc"), + authored_wi(id: "2-nbd-serve-held-session-lease", done: true, content: "**nbd-serve-held-session-lease** — NbdProxyServeSession intent with port/pid/cmdline/ISO/token fingerprint; classification + plan INSTANTIATE `std.upsert_decision` (`ObservationVerdict` + `UpsertDecision

`; domain facts as the P payload — do NOT mint a parallel lease vocabulary, cf. the fork-census 2026-07-03). RED: foreign 10809 no kill; stale matching session drains only. Live consumer: srv3 actuator.", intricacy: IntricacyHigh, volume: VolumeMedium, repo: "gunbc"), authored_wi(id: "2-srv3-boot-action-diagnostic", done: false, content: "**srv3-boot-action-diagnostic — Redfish vs ipmitool fallback state machine** — separate transports for BmcBootAction; boot refused unless serve RunningExpected; NoRebootObserved → optional IpmiResetFallback with separate approval; OutOfBandHostActionReceipt until modeled.", intricacy: IntricacyHigh, volume: VolumeSmall, repo: "gunbc"), authored(id: "2-os-install-generic-naming", done: false, content: "**os-install generic naming cleanup** — rename generic behavior tests/modules away from `srv3_*` where testing credential resolution, remaster classification, workflow escalation; keep srv3 only in instance fixtures (`srv3_pre_install_lease_table`, `srv3_seeded_install_media_artifact`). Post-#6134."), ], @@ -283,7 +287,7 @@ fn section_2() -> RoadmapSection { authored(id: "2-fleet-hardening", done: false, content: "**the return happened ungated** — #6111 put required CI back on srv1/srv2 by operator call, accepting interim OOM/sccache exposure; the items below are the gates the return *should* have had, now owed as hardening. Ubicloud remains the burst/fallback offer (and the slot-shape template the admission model generalizes)."), authored(id: "2-session-slice", done: false, content: "**SessionSliceEnforcement + verified-effective caps** — agent-session cgroups have no citable verified-effective cap (the residual over-commit vector on srv1/srv2); the humming apply-rule stands: runner caps must not tighten while sessions are uncapped and oomd is absent."), authored_doc(id: "2-oom-consumer", done: false, content: "**OOM classification consumer** — `ClusteredOutOfMemoryKill` is modeled but absent from the active infra-retry signature roster; build the consumer so an OOM is first-class, never EAGAIN-shaped.", path: "docs/plans/ci-oom-reclassification.md"), - authored(id: "1-sched-resource-aware", done: false, content: "**resource-aware scheduler (implementation)** — implements the signed [bounded-input / cost-envelope scheduling](docs/plans/bounded-input-cost-envelope-scheduling.md) design: (A) per-shard peak-RSS plumbing → (B) `Runnable.cost` with Predicted `CostEnvelope` → (C) scheduler reads cost, static side-channel deleted → (D) Measured falsifies Predicted, calibration loop retires data rows (#5431 instrument). Construction invariant: more memory → more width → more throughput, no `.dag` edits. [tracker](docs/plans/resource-aware-scheduler.md)"), + authored(id: "1-sched-resource-aware", done: false, content: "**resource-aware scheduler (implementation)** — re-base required: the signed design's authored widths + per-shard peak predictions were deleted by the 2026-07-12 adaptive-width ruling (gunbc_ci_adaptive_width_note) in favor of the runtime AIMD memory governor; the governor's declared dissolve-on is graph-derived per-node demand (CostAccount.space measured — witness-realization measured-space lane, #6738 P1–P6 + #6855 P4 advisory packing width landed). Re-base phases A–C onto governor + measurement lane before dispatching. [tracker](docs/plans/resource-aware-scheduler.md)"), authored_pp(id: "1-budget-tree", done: false, content: "**resource budget tree** — admission (construction) · conserve-lens (honest residue) · runtime reconcile (fail-closed handler), three verdicts never conflated; subsumes spawn-width/placement/compile-jobs as consumer leaves. Protective only when paired with an enforcement actuator (cgroup `memory.max`, operator-fenced).", carriers: [ptr(label: "carrier", path: "dag/product/budget_tree.dag"), ptr(label: "grounding", path: "docs/plans/budget-tree.md")]), authored(id: "1-placement-authority", done: false, content: "**one Placement authority** — jobs (GitHub) · threads (`spawn_width`) · sessions (ctrl capacity) are 3 forks of \"put work on a host\"; `Placement`/`Materialization` are modeled but inert — CI consuming them is the lane's real deliverable."), ], @@ -305,12 +309,12 @@ fn section_3() -> RoadmapSection { section_group( label: "Audit — green by execution, red by perturbation", nodes: [ - authored_wi(id: "3-audit-affected-set", done: false, content: "**affected-set lens** *(the operator's named example)* — witness-level skip is LIVE on the floor (#6061); prove it: (a) **soundness** — construct a diff that MUST re-run a witness and assert it runs (a skipped-but-affected witness is the fail-open catastrophe); (b) **effectiveness** — receipts on real scoped diffs (skip counts + wall-clock delta, not claims); (c) **fail-closed default** — a provenance gap falls back to run-all, witnessed RED-on-perturb. The node-closure half (#6105) inherits the same receipt obligation before it may prune.", intricacy: IntricacyHigh, volume: VolumeMedium, repo: "gunbc"), + authored(id: "3-audit-affected-set", done: true, content: "**affected-set lens — discharged by a standing mechanism (audit 2026-07-23)**: (a) soundness = the 4-hourly falsifier runs the corpus cold with predictions recorded, counted divergence is the RED — and it discriminated live (the 07-16..07-21 red period was real roster gaps, healed #7083; alert loudness #7022); (b) effectiveness = discovery-flip receipt 8→~1,721 witnesses/PR (ci_spec_discovery_flip_note, operator acceptance 2026-07-09) + regen affected-set ~4m45s/PR (#6732) + compile-clean closure scoping (#6658); (c) fail-closed = #6525 ReadsLiveTree never-skip and a provenance gap REFUSES, never widens (the original run-all wording predates the §5 absorbing-fallback ruling)."), sign(rn: owned(rn: with_plan(rn: authored_wi(id: "3-audit-gate-inventory", done: true, content: "**mechanism inventory with red-controls** — census every wired gate/lens/cache (floor-plan roster + `commit_workflow`): what it claims · its discriminating RED witness · its last execution receipt. Anything without a red-control gets one or gets demoted/deleted. The inert-lens backstop (#5433) covers *wiring*; this covers *claim-vs-behavior*.", intricacy: IntricacyMedium, volume: VolumeLarge, repo: "gunbc"), path: "docs/plans/mechanism-inventory-red-controls.md"), owner: "dispatched 2026-07-01 · adhoc-c67edbed-916"), s: signed(by: "operator", works: true, scope_equivalent: true, as_expected: true)), authored(id: "3-audit-cache-honesty", done: false, content: "**cache honesty re-receipt** — re-run the warm==cold purity oracle against CURRENT main (616/616 was pre-reset), and close the sccache exit-0-no-binary class (below); a cache that lies is worse than no cache."), authored_wi(id: "3-audit-artifact-freshness", done: false, content: "**artifact-freshness gate** *(operator ask: \"we need a freshness gate, if we don't already have one\")* — we half-do: the per-PR drift gate proves committed==emitted for the PR's OWN tree, but drift still LANDED on main (`.gitignore` stale vs its authority since #6097; found and healed by #6110/#6111) because admission never re-validates against CURRENT main — green-on-branch is not green-on-main. The closing mechanism is the §2 merge-admission freshness block (HELD); this item is its receipt pair: (a) reproduce the landed-drift path as a RED witness, (b) confirm the freshness block refuses it once un-HELD.", intricacy: IntricacyMedium, volume: VolumeSmall, repo: "gunbc"), - authored(id: "3-audit-gate-disagreement", done: false, content: "**one tree, one verdict** — 2026-07-01 live finding: `dag_compile_clean_gate` was GREEN while the discovery-corpus resolve of the same tree was RED (`extdeps.shell` module collision, silent last-root-wins shadowing; de-fork + loud-collision wall shipped as the hotfix). Two resolve paths gave two verdicts on one corpus — enumerate every place a module index is built, and make their collision/ordering semantics ONE authority so a gate cannot be green on a tree the floor cannot resolve."), - authored(id: "3-enforcement-intent", done: false, content: "**enforcement intent + model-quality walls** *(operator-directed 2026-07-02; §3 un-shelve — displaced cost: repeated manual \"what is enforced, by what lens, over what corpus\" joins; CI-killing quadratics; repeated dual-representation/anemia rediscovery)* — model the operator's recurring standing directives as durable `StandingIntent` rows and gate the relationship (intent ⇄ `LensContract` ⇄ `CoverageReceipt`) fail-closed, so a mechanism *claiming* enforcement is complete only when the gate proves the claim **from receipts, not self-declared contract claims**. One new authority (`StandingIntent`); everything else extends existing machinery (`LensRegistryEntryV0` → `LensContract`; reuse `ConstructionJustification` / `subject_roster`; consume `intent_linearity` / `self_applying_lenses`). Anti-overcomplication: no lens may claim *repo-wide* / *blocking* / *complete* / *self-applying* unless the gate can prove it. Rollout: rows live; gate Blocking on contract consistency; object rules AuditOnly until receipts land. Children, A→C before object rules D/E: **A** StandingIntent carrier + LensContract extension (`ConsumerKind`/`ConsumerRequirement` NOT hardwired to `FloorGate`; `EnforcementMode` order `Advisory < AuditOnly < Blocking` modeled) · **B** enforcement_intent_gate contract-consistency reds (over `CoverageReceipt`s) · **C** complexity.repo-wide first proof (3 legs red today, no `decl_facts` dep) · **D** complexity R1 accumulator-in-copied-port object rule (HOLDS behind #6155) · **E** anemia/consolidation first model-quality consumers (suggest a consolidation target, not just warn). [design](docs/plans/enforcement-intent-design.md)"), + superseded(id: "3-audit-gate-disagreement", by: "namespace-only resolution lane (operator-signed 2026-07-06) — docs/plans/namespace-resolution-design.md", content: "**one tree, one verdict** — the concrete forks dissolved: #6950 gate loader runs both closures (the exact gate-green/floor-red fork), #6935 reference_resolution_facts builtin de-forked the module-graph host; the systemic one-resolution-authority ask IS the namespace lane. Residual to carry: the gate-equivalent local invocation is still flag-sensitive (--dependency-pool-index primary-precedence)."), + authored(id: "3-enforcement-intent", done: false, content: "**enforcement intent + model-quality walls** — substantially LANDED, re-based 2026-07-23: carrier family src/v2/lens/enforcement/ (standing_intent, contract, gate, receipts) + enforcement_live.dag on main; children A+B via #6756 (Question-0 lens-module gate, StandingIntent fail-closed); C carrier standing_intent_complexity_repo_wide exists; D's object rule effectively landed (#6527 accumulator-copy as required root-grain compile lens + #6540); E first consumer merged (model_anemia lens). Post-landing churn: #7070 de-enrolled lens_module_gate from the compile door (corpus-grain invariant, tree-grain roster). REMAINING: fold that churn in, finish the C receipts, close the DESIGN open thread. [design](docs/plans/enforcement-intent-design.md)"), ], edges: [], ), @@ -324,9 +328,9 @@ fn section_3() -> RoadmapSection { section_group( label: "Open floor holes", nodes: [ - authored(id: "1-nightly", done: false, content: "**nightly full-corpus selector-backstop** — per-PR selection is only sound because nightly runs everything; ⚠ CI-gen load-bearing"), + authored(id: "1-nightly", done: true, content: "**full-corpus selector-backstop — live at 4-hourly cadence (audit 2026-07-23)**: falsifier.yml cron runs the corpus cold with predictions recorded (the flip note names it the selection's soundness governor); falsifier-alert (#7022) closes the silent-red loudness gap; green again per #7083. Regen's cold control is separate (unconditional main-push regen)."), authored_pp(id: "1-builtin-registry", done: false, content: "**tree-scoped builtin registry** (fail-closed) — the global seed registry leaks intrinsics into the substrate compile, making compile-clean falsely green; instance fix #5452, class fix (partition) open", carriers: [ptr(label: "force-check plan", path: "docs/plans/compile-clean-forcecheck.md")]), - authored(id: "1-sccache-falsegreens", done: false, content: "**kill sccache false-greens** — exit-0-no-binary; build-verify asserts the artifact exists + is fresh (partly landed in `ci.yml`)"), + authored(id: "1-sccache-falsegreens", done: false, content: "**kill sccache false-greens** — exit-0-no-binary CLOSED: claim_executor --verify-build-artifacts asserts every declared release binary exists + is executable at 3 ci.yml sites (#6472-era); deploy rebuild-flake killed by artifact reuse (#6810). REMAINING residue: freshness not asserted; sccache local-disk content_verified_on_read=false with live repro (#7031 — the cache-lies class is confirmed live); the ci_spec absorbing retry-fallback removal is srvN build-cache STEP-2, gated on srv1 (STEP-1 #6835)."), ], edges: [], ), @@ -345,16 +349,16 @@ fn section_4() -> RoadmapSection { plain(id: "shelf-ergonomics", content: "**fold-ergonomics lane** — inert-abstraction lens · non-fold-residue audit · staging combinator · ban source comments [charter](docs/plans/fold-ergonomics.md) [residue catalogue](docs/plans/non-fold-irreducible-residue-catalogue.md) [debt sample audit](docs/plans/real-debt-syntactic-sample-audit.md) [eval-bind PROPOSE](docs/plans/eval-bind-node-eval-propose.md)"), plain(id: "shelf-failclosed-meta", content: "**fail-closed meta band** — `Value::Null` split (the deep root) · Disposition carrier · reference grounding · cardinality refinement · expressibility frontier · reachability-completeness lens · axiom+syllogism lens · self-applying lenses · inert-lens promotion + gate-hygiene residue [lockdown](docs/plans/fail-closed-lockdown.md) [fork plan](docs/plans/model-realization-fork.md) [Disposition](docs/plans/disposition-carrier.md) [reference grounding](docs/plans/reference-grounding-migration.md) [cardinality](docs/plans/cardinality-refinement.md) [P1 where-lowering](docs/plans/p1-where-clause-lowering.md) [frontier](docs/plans/expressibility-frontier.md) [inert-layer lens](docs/plans/inert-layer-lens.md) [axiom lens](docs/plans/axiom-syllogism-lens.md) [self-applying](docs/plans/self-applying-lenses.md) [construction rule](docs/plans/construction-justification-rule.md)"), plain(id: "shelf-rust-gate", content: "**rust-gate `.dag`→rust coverage wall (edge-b)** + stage0 clone-census ratchet [brief](docs/plans/edge-b-rust-dag-provenance-brief.md)"), - plain(id: "shelf-complexity", content: "**complexity budget whole-codebase** + the algebraic-rewrite construction engine (O(n²)→O(n) catalog, `Unknown` dissolution) [rewrite plan](docs/plans/algebraic-rewrite-optimization.md)"), + superseded(id: "shelf-complexity", by: "live complexity-enforcement carriers — #6527 accumulator-copy required compile lens · #6540 affected-set floor enforcement · #6632 per-op cost derivation", content: "**complexity budget whole-codebase** — un-shelved and live in tree; the algebraic-rewrite construction engine remains parked ([rewrite plan](docs/plans/algebraic-rewrite-optimization.md))."), plain(id: "shelf-testgen", content: "**testgen oracle + wiring-liveness family** (compile-time wiring lens ✓ #5679 · pre-send guard ✓ #5683 stand; the generator/preflight expansion parks) [method](docs/plans/testgen-oracle.md) [wiring](docs/plans/wiring-liveness-preflight.md)"), plain(id: "shelf-caching-completion", content: "**caching completion** — `realize(subject)` one door (P2) · M5 fixture-store · native `content(T)` (P5) · B1 generic-instantiation / B2 cross-tree content-hash blockers · one Materialization kernel · shared secrets model [loop](docs/plans/realization-measurement-loop.md) [M4](docs/plans/m4-universal-hermetic-corpus.md) [M5](docs/plans/m5-fixture-store-consolidation.md)"), plain(id: "shelf-deforks-small", content: "**CI inline-shell de-fork · interpreter terminal-output de-fork** (seed forks of modeled authorities; both shrink as v1 burns down) [emission-ingestion](docs/plans/emission-ingestion-inverse.md)"), plain(id: "shelf-idea-machine", content: "**idea machine** — ingest-at-large · English closure/round-trip · cross-media (JSON/react/diagram) · `Medium` homomorphisms · format-model C4–C6 · fidelity compose-up · eval generalization · invert-hand-maintained residue [plan](docs/plans/idea-machine.md) [format reconciliation](docs/plans/format-model-reconciliation.md) [invert](docs/plans/invert-hand-maintained.md)"), - plain(id: "shelf-shell-tail", content: "**shell-emission slices 3–4 (census-rescoped)** — live_deploy → thin-run/typed-effect candidate (runtime-present; not a golden to freeze) · bmc_token_federation (two Do rows) → ci_workflow RunSteps → githooks thin shim [plan](docs/plans/shell-emission-model.md)"), + superseded(id: "shelf-shell-tail", by: "shell→intent arc — DESIGN open thread + docs/plans/shell-to-dag-residual-census-and-arc-completion.md", content: "**shell-emission slices 3–4** — absorbed: #6750 routed bmc_token_federation Do rows + ci_workflow RunSteps through orch_emit_step; githooks thin shim in tree; live_deploy re-modeled on the fleet-reconcile spine (#6820/#7086), not a frozen golden."), plain(id: "shelf-typescript", content: "**TypeScript first-class emit + TS self-host** — END GOAL UNCHANGED (both realizations, per plan do-not-relitigate); resumes after the Rust fixed point [gap census](docs/plans/typescript-gap-census.md)"), plain(id: "shelf-language-frontier", content: "**language-target self-host frontier** — the get-to-self-host path for all emission languages (Rust as model; Verilog/SPICE/LLVM as design-stress falsifiers); solve resolved as higher-order not a primitive [frontier](docs/plans/language-target-self-host-frontier.md) [solve rationale](docs/plans/solve-higher-order-design.md)"), - plain(id: "shelf-html-dashboard", content: "**HTML/React + live dashboard lane** — page ✓ (#6010) and srv1 deploy ✓ (#6030) keep running as-is; interactivity · idea-input · demo park. The minimal **stateless-frontend fabric slice is active in §2** only as a storage+compute+route consumer, not as the full dashboard/product lane (the CD *transport* fix is also §2 live work)"), - plain(id: "shelf-session-dashboard", content: "**session dashboard + roadmap-as-spawner** — the *automatic* spawn bridge stays fail-closed paused; §1–§3 sized nodes are the only dispatch surface (§3 audit items are deliberately dispatchable — the operator's audit lanes). The operator-clicked **dispatch actuator** slice is un-shelved into §2 (2026-07-03) [plan](docs/plans/roadmap-spawner.md)"), + superseded(id: "shelf-html-dashboard", by: "gunb.ai site-subsumption lane (#6927 Phase-0) + gunbc-served dashboard (belt B, #6940)", content: "**HTML/React + live dashboard lane** — both halves now owned elsewhere: the page/frontend by the site-subsumption lane; the blessed keep-running JS server is a named §3 dual representation slated for deletion by belt B."), + superseded(id: "shelf-session-dashboard", by: "conveyor-belt lane — belt A+B merged (#6940), belt_dispatch_node single dispatch authority (#6914), go-live #7096", content: "**session dashboard + roadmap-as-spawner** — the operator-clicked dispatch actuator became the conveyor belt and is LIVE. Still true from this row: the automatic spawn bridge stays fail-closed paused."), plain(id: "shelf-gunbhub", content: "**gunbhub** (own the Git/CI engine, closes G6) · internal repo model · compute fabric as a sellable piece"), plain(id: "shelf-privacy", content: "**privacy / isolation model for the compute fabric** — trust boundaries, tenant isolation, what the fabric may observe about a workload; was compute-fabric downstream work pre-reset, parked here so it is not lost (`trust_class` on `RunShape` is its active §2 seam). Includes committed-secret references (operator 2026-07-02, not urgent): a typed `SecretRef` — GCP Secret Manager resource name + version/content-hash — so sensitive facts (router serial, WAN MAC, public prefixes, credentials) commit as model-legible references while values stay in Secret Manager; redaction by construction (public shapes carry no raw-value field); first consumer: the network-identity observation fixtures."), plain(id: "shelf-structural-walls", content: "**structural correctness walls (standing, not active)** — generated-output gate · coproduct exhaustiveness · cross-representation equality · oracle-method map; they keep gating, no expansion work dispatches from here"), @@ -375,7 +379,7 @@ fn task_sheet_lead_lane() -> RoadmapSection { label: "1 · Main to actual green (audit receipts, 2026-07-22)", nodes: [ authored(id: "ts-falsifier-nfr", done: true, content: "**falsifier dark since 2026-07-16 — roster burn-down** — every 4-hourly cold run red on `non_fold_residue_clean_holds` + `non_fold_residue_no_unrostered_or_stale`, logged as predicted=unaffected / actual=red divergences. Root-caused 2026-07-22 by local receipt (`nfr_roster_receipt`): 3 unrostered sites, 0 stale — `dag/gunbc/host_converge_slice1.dag::host_converge_slice1_host_result_all_valid` + `::host_converge_slice1_host_result_applied_count` (landed #7009) and `dag/gunbc/host_hygiene_reaper.dag::action_kills_build_cache_server` (landed #7026). LANDED with this sheet update: the 3 roster rows (reason + dissolution trigger each, the #6691 shape) are in `cli_run.rs`; receipt `nfr_roster_receipt` unrostered=0 stale=0 and the lens fn evaluates true by execution. The falsifier goes green on its next scheduled run and #7032 auto-closes — if it reds on anything else, that is a NEW find, not this one."), - authored(id: "ts-deploy-tail", done: false, content: "**srv1 deploy keeps breaking and reds main while the floor is green** — 13 of 2026-07-22's 21 main-run failures are `deploy_dashboard_srv1`, not the floor: `gunbc-tree-sync.service` restart control-process failure (fix in flight: `session/sunny-owl-513`, receipt run 29928424523) after earlier `gunbc-roadmap.service` /healthz ServiceNotReady. Two halves: converge the srv1 units, and decide whether the deploy verdict should share the ci run's conclusion — main-green must mean code-green. The deeper fix is §2's CD-transport node; note `gunbc-roadmap.service` is also item 3's dispatch surface, so this fix is its prerequisite. UPDATE 2026-07-22 late: both halves of the unit fix are in — the tree-sync fix (16:34) and #7077's measured readiness bound (30s→120s; four srv1 starts at 35–39s prove the old bound red every SUCCESSFUL start). The tail executes for the first time on the first main run whose floor passes (post-#7080); check this row off on the first green deploy job, and keep the verdict-sharing question open. FIRST EXECUTIONS (21:49–21:50, both red, DIFFERENT causes — receipts from runs 29957321270/29957141552): (a) the #7077 run died at tree-sync — the .git/ rsync exited 23 (partial transfer) while a SECOND deploy job ran concurrently 18s later on another runner slot against the same /opt/gunbc target; deploy jobs have no concurrency group and ran out of commit order (newer commit deployed first, older second — even on success srv1 converges to the OLDER tree, last-writer-wins). NEW work: serialize the deploy (workflow concurrency group or host-side lock) and stop rsyncing .git/ from a live reusable runner checkout — the CD-transport node's case sharpens. (b) the #7080 run got past tree-sync, restarted the unit (active, 34s into its ~35–39s startup) and probed with the OLD 30s bound — its tree predates #7077; the known class, already fixed. The first honest 120s-bound deploy is the next main run carrying both fixes (#7058 merge, in flight at write time). THIRD EXECUTION (run 29961193892, 22:51): floor green a THIRD consecutive time, deploy red AGAIN at the same tree-sync .git rsync exit 23 — with NO concurrent deploy this time, which RECLASSIFIES the failure from race to a deterministic per-source-checkout condition: succeeded from srv1-03's checkout (21:49), failed twice from srv1-05's (21:49, 22:51). Leading suspect: service-user-unreadable files inside the runner checkout's .git/ (the oneshot reads ghrunner's checkout as User=service-user; a 0600 .git/config carrying the actions auth extraheader would explain exit 23 exactly — and note syncing .git/config to /opt/gunbc would be a CREDENTIAL LEAK if it ever succeeded, so excluding config from the .git sync is both the likely fix and a hardening). LOUDNESS gap, same class the status-tail was added for: the diagnosis shows exit 23 but never the per-file rsync errors (they live in the unit journal) — extend the capture to a journalctl tail so the failing paths are NAMED. The 120s readiness bound remains unexercised until tree-sync converges. RESOLUTION 2026-07-22 late: journal receipt named the root — ONE ghrunner-owned 0600 fetch marker (objects/pack/pack-25d0…keep) unreadable to the unit principal, deterministic on srv1-05; AND /opt/gunbc/gunbc/.git/config was carrying an actions extraheader auth token from the blanket sync (a real credential leak). Operator hand-scrubbed the token and removed the stale marker; the construction fix (whitelist .git sync — HEAD, objects minus fetch transients, packed-refs, refs, terminal exclude wall) MERGED with #7086, making both classes unwritable. Dashboard STAYS on srv1 (operator decision 2026-07-22); the srv3 move was assessed — redeploy-not-migration, ~1–2 days via HostIdentity spec parameterization shared with #7027 G1, plus service-account + claude-auth seeding — and parked."), + authored(id: "ts-deploy-tail", done: true, content: "**srv1 deploy keeps breaking and reds main while the floor is green** — 13 of 2026-07-22's 21 main-run failures are `deploy_dashboard_srv1`, not the floor: `gunbc-tree-sync.service` restart control-process failure (fix in flight: `session/sunny-owl-513`, receipt run 29928424523) after earlier `gunbc-roadmap.service` /healthz ServiceNotReady. Two halves: converge the srv1 units, and decide whether the deploy verdict should share the ci run's conclusion — main-green must mean code-green. The deeper fix is §2's CD-transport node; note `gunbc-roadmap.service` is also item 3's dispatch surface, so this fix is its prerequisite. UPDATE 2026-07-22 late: both halves of the unit fix are in — the tree-sync fix (16:34) and #7077's measured readiness bound (30s→120s; four srv1 starts at 35–39s prove the old bound red every SUCCESSFUL start). The tail executes for the first time on the first main run whose floor passes (post-#7080); check this row off on the first green deploy job, and keep the verdict-sharing question open. FIRST EXECUTIONS (21:49–21:50, both red, DIFFERENT causes — receipts from runs 29957321270/29957141552): (a) the #7077 run died at tree-sync — the .git/ rsync exited 23 (partial transfer) while a SECOND deploy job ran concurrently 18s later on another runner slot against the same /opt/gunbc target; deploy jobs have no concurrency group and ran out of commit order (newer commit deployed first, older second — even on success srv1 converges to the OLDER tree, last-writer-wins). NEW work: serialize the deploy (workflow concurrency group or host-side lock) and stop rsyncing .git/ from a live reusable runner checkout — the CD-transport node's case sharpens. (b) the #7080 run got past tree-sync, restarted the unit (active, 34s into its ~35–39s startup) and probed with the OLD 30s bound — its tree predates #7077; the known class, already fixed. The first honest 120s-bound deploy is the next main run carrying both fixes (#7058 merge, in flight at write time). THIRD EXECUTION (run 29961193892, 22:51): floor green a THIRD consecutive time, deploy red AGAIN at the same tree-sync .git rsync exit 23 — with NO concurrent deploy this time, which RECLASSIFIES the failure from race to a deterministic per-source-checkout condition: succeeded from srv1-03's checkout (21:49), failed twice from srv1-05's (21:49, 22:51). Leading suspect: service-user-unreadable files inside the runner checkout's .git/ (the oneshot reads ghrunner's checkout as User=service-user; a 0600 .git/config carrying the actions auth extraheader would explain exit 23 exactly — and note syncing .git/config to /opt/gunbc would be a CREDENTIAL LEAK if it ever succeeded, so excluding config from the .git sync is both the likely fix and a hardening). LOUDNESS gap, same class the status-tail was added for: the diagnosis shows exit 23 but never the per-file rsync errors (they live in the unit journal) — extend the capture to a journalctl tail so the failing paths are NAMED. The 120s readiness bound remains unexercised until tree-sync converges. RESOLUTION 2026-07-22 late: journal receipt named the root — ONE ghrunner-owned 0600 fetch marker (objects/pack/pack-25d0…keep) unreadable to the unit principal, deterministic on srv1-05; AND /opt/gunbc/gunbc/.git/config was carrying an actions extraheader auth token from the blanket sync (a real credential leak). Operator hand-scrubbed the token and removed the stale marker; the construction fix (whitelist .git sync — HEAD, objects minus fetch transients, packed-refs, refs, terminal exclude wall) MERGED with #7086, making both classes unwritable. Dashboard STAYS on srv1 (operator decision 2026-07-22); the srv3 move was assessed — redeploy-not-migration, ~1–2 days via HostIdentity spec parameterization shared with #7027 G1, plus service-account + claude-auth seeding — and parked."), authored(id: "ts-native-flip-revert", done: false, content: "**first NativeRouted flip reverted by receipt — the frontier working as designed** — main run 29963619401 (#7069 merge, srv2-05) redded `emit_on_demand_family_crate_pr_native_agreement_holds` WARM (compile_skipped=true ×3, false in 496ms): a genuine native-vs-eval divergence or member-run failure, NOT cold cache. Remedy per design: complement + meet_join back to `InterpretedRetained agreement_red_on_main` — a two-row data edit, receipt on the carrier (`routed_flip_reverted_note`), investigation off the merge-critical path, falsifier cold control still exercising both legs. Named loudness gap to close BEFORE re-flip: the agreement fn's false carries no located member and no value pair — a divergence receipt must name which member and both answers."), authored(id: "ts-queue", done: false, content: "**queue + zombie hygiene** — ~18 runs/hour arriving against a 60–97-min green wall; main pushes queue behind PR traffic; cancel zombie queued run 50073 (`session/clever-hawk-862`, queued 2026-07-13); revisit main-push priority."), authored(id: "ts-overnight", done: true, content: "**overnight main floor breakage healed** — the 00:44–02:04 cluster (DAG compile failure + ci_deploy_sudoers typecheck) was fixed on main by ~02:04; recorded so the day's red accounting separates it from the deploy-tail reds."), @@ -404,7 +408,7 @@ fn task_sheet_lead_lane() -> RoadmapSection { label: "2 · CI actually functional — what it takes, what the roadmap already claims", nodes: [ authored(id: "ts-ci-definition", done: false, content: "**definition — CI is functional when (a) a red means a real defect, (b) a green is trustworthy corpus-wide, and (c) the verdict arrives before merge.** Today none of the three hold: deploy reds mask code health (item 1), predict-skip hides corpus reds until the falsifier, and merges land 0–17 min after open while a green run takes 60–97 min."), - authored(id: "ts-lying-stamp", done: false, content: "**kill the recurrence class — corpus-scan witnesses predict-skipped** — 4th occurrence per the nfr roster's own dated blocks: hygiene witnesses stamped `SubstrateInputsOnly` while their counters walk the whole corpus, so per-PR selection skips them and only the falsifier reds, days later. Decide once: re-stamp `ReadsLiveTree` (never-predict-skip; sub-ms at floor scale) vs falsifier-red as a merge blocker. Census machinery landed #7070."), + authored(id: "ts-lying-stamp", done: false, content: "**kill the recurrence class — corpus-scan witnesses predict-skipped** — 4th occurrence per the nfr roster's own dated blocks: hygiene witnesses stamped `SubstrateInputsOnly` while their counters walk the whole corpus, so per-PR selection skips them and only the falsifier reds, days later. Decide once: re-stamp `ReadsLiveTree` (never-predict-skip; sub-ms at floor scale) vs falsifier-red as a merge blocker. Census machinery landed #7070. 5TH OCCURRENCE (2026-07-23): #7088 landed gate_in_cheap_floor_membership + spec_enrolls_gate unrostered in ci_floor_plan.dag; caught by an unrelated dag-touching PR running the whole-corpus nfr receipt (#7104), backfilled per the roster precedent."), authored(id: "ts-merge-gate", done: false, content: "**CI is not a merge gate (re-evidence)** — 0–17-minute creation→merge latencies observed in the merge wave while a green run takes 60+ min, so verdicts land post-merge and main is the integration testbed; re-evidences §2's merge-admission HELD-state node — while it stays HELD and the falsifier is dark, the corpus has no pre-merge wall at all."), authored(id: "ts-floor-memory", done: false, content: "**floor memory ceiling** — falsifier floor pinned at the 16 GiB cgroup memory.high with ~33 GB swap, sustained PSI stalls, and ~18 min of post-failure residual burn; #7000 (srv3 MemoryHigh/MemoryMax caps) landed 2026-07-22 — confirm the next falsifier runs reflect the caps; residual lineage #6848 → #7030."), authored(id: "ts-ci-claimed", done: false, content: "**already claimed in the roadmap — dispatch from these lanes, do not re-plan them**: §0 ① compile wall + ③ affected-set live in CI; §2 floor-throughput group (serial compile-clean wall · shard A ✓ / shard B · within-run double-resolve · resolve-cache default-on) targeting floor <1min; §2 workload-class admission + cap/admission de-conflation; §3 audit rows (affected-set soundness receipts · one tree one verdict · cache honesty re-receipt); the CI-onto-v2 native-routing lane (#7069, parity-gated). What the audit adds is only sequencing: falsifier green first (item 1), then selection honesty, then speed — a fast CI that lies is worse than a slow one."), @@ -430,7 +434,7 @@ fn task_sheet_lead_lane() -> RoadmapSection { section_group( label: "3 · Work intake — dispatch from the roadmap, not ad hoc", nodes: [ - authored(id: "ts-dispatch-elevate", done: false, content: "**roadmap-driven dispatch — the machinery is LANDED; three gaps to go-live (assessed 2026-07-22)**: `gunbc serve` on srv1 serves the LIVE roadmap with `POST /dispatch/NODE_ID` invoking `belt_dispatch_node` in-process; the belt observes fail-closed (tmux ls), reconciles the ready frontier, and spawns `git worktree add` + tmux running claude with the FILLED dispatch brief as appended system prompt (effort mapped from node Intricacy), deterministic session UUID, typed refusals throughout; `belt_run_once_json` is the CLI tick for receipts. Gaps: (1) TREE FRESHNESS — srv1's tree/binary have been stale since belt B merged because every deploy failed; unblocks with the first green deploy post-#7086; (2) ONE LIVE END-TO-END RECEIPT — never collected with real claude (tests used a fake): ssh srv1, run belt_run_once_json once, converge whatever typed refusals it names (likely tmux/claude/claude-auth for the service user); (3) SIZED NODES — dispatchability requires intricacy/volume + Accept line + deps-done; the task-sheet authored() rows are unsized tracking rows BY DESIGN, so size the lane nodes you actually want dispatched. Auth precondition: 3b's dispatch-auth row before the button is exposed beyond the tailnet. GO-LIVE RECEIPT (2026-07-23, live on srv1): gap 2 CLOSED by execution — `POST /dispatch/2-dispatch-actuator` → `spawned`; independent read-back: `tmux ls` shows `gunbc-dispatch-2-dispatch-actuator`, worktree at `/opt/gunbc/dispatch-worktrees/2-dispatch-actuator` on branch `dispatch/2-dispatch-actuator`, REAL claude v2.1.170 running with the filled brief (`--effort high`, deterministic session UUID) and its transcript file under `~/.claude/projects/-opt-gunbc-dispatch-worktrees-2-dispatch-actuator/`; second POST → `already_live` (idempotent); bogus node id → `node_not_found` (typed RED, live). One refusal converged: claude's per-path workspace-trust dialog blocked the first spawn (`--dangerously-skip-permissions` does NOT cover it — same finding as ctrl's container entrypoint trust seed); ancestor-dir trust inheritance was proven by execution (seeded parent → child skips the dialog), so the ONE root `/opt/gunbc/dispatch-worktrees` is now seeded in srv1's `~/.claude.json` — interim hand-provisioning of the same class as the host_layout paths, dissolves into the live_deploy membership. Gap 3 receipt: the live ready-set serves 13 sized ready nodes. Gap 1 CLOSED by execution: the #7091 main run (29967907137) went green through the deploy tail — the first green `deploy_dashboard_srv1` post-#7086 — and srv1 converged by independent read: `/opt/gunbc/gunbc` HEAD == main HEAD 960bc8548, binary refreshed, unit active, `/healthz` ok. NEW GAP found live: re-dispatch after Stop is broken — own row below. CLAUDE DEPENDENCY MODELED (2026-07-23, same PR): the trust hand-seed now has a modeled home — `extdeps.llm.cli` carries claude's trust-store facts (`~/.claude.json` projects map, flag `hasTrustDialogAccepted`, ancestor-inheritance; classifier reuses the JSON grammar's string-aware value parser, not a brace scan) and the belt PREFLIGHTS claude-on-PATH + trust-seed-for-worktree-root before any actuation (typed `spawn_failed` steps `claude-cli`/`claude-trust-*` — previously a missing claude spawned a tmux pane that died instantly behind a fabricated `spawned`, and an unseeded root HUNG the session on the dialog); refuse-with-instructions, not auto-seed (the store is claude's own runtime-mutable file — a read-modify-write races the upstream writer), so seeding itself still dissolves into live_deploy. UI FORK FOUND LIVE + FIXED (2026-07-23): the dispatch button read the retired belt-A `ok`/`node` response shape while belt B answers `status`, so EVERY successful click rendered 'failed' (the operator's `5-regen-cutover` click had in fact spawned); the page now derives its ok-predicate from `belt_dispatch_ok_status_labels` — one wire vocabulary with the serve JSON (`belt_dispatch_status_label`), witness-glued to `belt_dispatch_result_ok`, page witness holds a RED on `j.ok`."), + authored(id: "ts-dispatch-elevate", done: true, content: "**roadmap-driven dispatch — the machinery is LANDED; three gaps to go-live (assessed 2026-07-22)**: `gunbc serve` on srv1 serves the LIVE roadmap with `POST /dispatch/NODE_ID` invoking `belt_dispatch_node` in-process; the belt observes fail-closed (tmux ls), reconciles the ready frontier, and spawns `git worktree add` + tmux running claude with the FILLED dispatch brief as appended system prompt (effort mapped from node Intricacy), deterministic session UUID, typed refusals throughout; `belt_run_once_json` is the CLI tick for receipts. Gaps: (1) TREE FRESHNESS — srv1's tree/binary have been stale since belt B merged because every deploy failed; unblocks with the first green deploy post-#7086; (2) ONE LIVE END-TO-END RECEIPT — never collected with real claude (tests used a fake): ssh srv1, run belt_run_once_json once, converge whatever typed refusals it names (likely tmux/claude/claude-auth for the service user); (3) SIZED NODES — dispatchability requires intricacy/volume + Accept line + deps-done; the task-sheet authored() rows are unsized tracking rows BY DESIGN, so size the lane nodes you actually want dispatched. Auth precondition: 3b's dispatch-auth row before the button is exposed beyond the tailnet. GO-LIVE RECEIPT (2026-07-23, live on srv1): gap 2 CLOSED by execution — `POST /dispatch/2-dispatch-actuator` → `spawned`; independent read-back: `tmux ls` shows `gunbc-dispatch-2-dispatch-actuator`, worktree at `/opt/gunbc/dispatch-worktrees/2-dispatch-actuator` on branch `dispatch/2-dispatch-actuator`, REAL claude v2.1.170 running with the filled brief (`--effort high`, deterministic session UUID) and its transcript file under `~/.claude/projects/-opt-gunbc-dispatch-worktrees-2-dispatch-actuator/`; second POST → `already_live` (idempotent); bogus node id → `node_not_found` (typed RED, live). One refusal converged: claude's per-path workspace-trust dialog blocked the first spawn (`--dangerously-skip-permissions` does NOT cover it — same finding as ctrl's container entrypoint trust seed); ancestor-dir trust inheritance was proven by execution (seeded parent → child skips the dialog), so the ONE root `/opt/gunbc/dispatch-worktrees` is now seeded in srv1's `~/.claude.json` — interim hand-provisioning of the same class as the host_layout paths, dissolves into the live_deploy membership. Gap 3 receipt: the live ready-set serves 13 sized ready nodes. Gap 1 CLOSED by execution: the #7091 main run (29967907137) went green through the deploy tail — the first green `deploy_dashboard_srv1` post-#7086 — and srv1 converged by independent read: `/opt/gunbc/gunbc` HEAD == main HEAD 960bc8548, binary refreshed, unit active, `/healthz` ok. NEW GAP found live: re-dispatch after Stop is broken — own row below. CLAUDE DEPENDENCY MODELED (2026-07-23, same PR): the trust hand-seed now has a modeled home — `extdeps.llm.cli` carries claude's trust-store facts (`~/.claude.json` projects map, flag `hasTrustDialogAccepted`, ancestor-inheritance; classifier reuses the JSON grammar's string-aware value parser, not a brace scan) and the belt PREFLIGHTS claude-on-PATH + trust-seed-for-worktree-root before any actuation (typed `spawn_failed` steps `claude-cli`/`claude-trust-*` — previously a missing claude spawned a tmux pane that died instantly behind a fabricated `spawned`, and an unseeded root HUNG the session on the dialog); refuse-with-instructions, not auto-seed (the store is claude's own runtime-mutable file — a read-modify-write races the upstream writer), so seeding itself still dissolves into live_deploy. UI FORK FOUND LIVE + FIXED (2026-07-23): the dispatch button read the retired belt-A `ok`/`node` response shape while belt B answers `status`, so EVERY successful click rendered 'failed' (the operator's `5-regen-cutover` click had in fact spawned); the page now derives its ok-predicate from `belt_dispatch_ok_status_labels` — one wire vocabulary with the serve JSON (`belt_dispatch_status_label`), witness-glued to `belt_dispatch_result_ok`, page witness holds a RED on `j.ok`."), authored_wi(id: "ts-dispatch-redispatch", done: false, content: "**re-dispatch after Stop is broken — the dispatch loop is one-shot per node (found live 2026-07-23)**: two failure classes, both proven by execution on srv1. (a) DEBRIS — Stop (`tmux kill-session`) leaves the worktree and the `dispatch/` branch behind, so the next POST is a typed `spawn_failed` (step git, `a branch named 'dispatch/…' already exists`); teardown/spawn must own the worktree+branch lifecycle (observe-then-decide, the same upsert_decision shape as session_lease — a worktree with uncommitted work must REFUSE removal, never silently delete). (b) SESSION-ID REUSE — after hand-cleaning worktree+branch, re-dispatch spawns tmux but claude exits 1: `Session ID is already in use` — the deterministic per-node UUID collides with the archived transcript, so a node is one-shot per host at the claude layer too. Fix direction: dedup does NOT depend on UUID determinism (observe keys on the tmux session NAME), so either resume the prior session on re-dispatch (`--resume ` — continues the node's prior work, arguably the RIGHT semantic) or derive a per-attempt UUID; either way the choice must be a typed observation arm, not a fabricated fresh-spawn. RED controls: re-POST after Stop must not be `spawn_failed`; a worktree with uncommitted changes must refuse teardown.", intricacy: IntricacyMedium, volume: VolumeSmall, repo: "gunbc"), authored(id: "ts-intake-discipline", done: false, content: "**until the actuator lands, this sheet is the intake queue** — new work enters as a row here or as a sized lane node with an Accept line, never ad hoc mid-session; dispatch top-down by the numbering; a session that discovers work files a row instead of chasing it."), authored(id: "ts-dispatch-lifecycle", done: false, content: "**each dispatched item is a real workflow, not a single hop (operator, 2026-07-23)** — stages: MODEL first (the concept/authority delta plus the acceptance claims, in a scratch file or its own PR), BRIEF generated from the row + model with the acceptance bar as checkable claims, IMPLEMENT, ANTAGONISTIC REVIEW against the brief (never against the PR's self-description), LAND with the verdict updating this sheet. The #7087 incident is the pattern to kill: worker hits design gaps, does half, flags the gaps honestly, the PR merges — and the item silently reads done. That is the absorbing fallback at the management layer: cannot satisfy the brief, so land what exists and let merge stand in for completion. The wall: MERGE IS NOT DONE — a merge certifies the diff is safe to land; only a review verdict moves an item's status."), @@ -491,14 +495,14 @@ fn task_sheet_lead_lane() -> RoadmapSection { nodes: [ authored(id: "ts-pr-audit", done: false, content: "**audit the remaining open PRs and decide each one's disposition** — merge · review-then-merge · fold into another lane · close; the 12 open at snapshot (16:30 UTC) are the children below; re-sweep after the merge wave settles, applying item 4's checklist and item 5's modeling audit to each."), authored(id: "ts-pr-7080", done: true, content: "#7080 layering gate false edges — the reference-derived producer misattributed prelude bare names, binders, and record-literal labels as cross-layer import edges (the one floor red left after #7082); fix verified pre-merge by a local red/green pair (gate witness false on main's tree, true with the PR applied, same tree same witness) — MERGED 2026-07-22 (7c222fc). Also the enabler for closure-derived Group membership (group 5a)."), - authored(id: "ts-pr-7078", done: false, content: "#7078 §13 alias APPLY as `.dag` workflow (`session/fierce-crab-363`) — ready; clean vs main, no generated artifacts touched, honest placeholder discipline (its equivalence witness is a self-declared scaffold, not the dual-run gate); Rust plan side retained until the real dual-run equivalence receipt."), + authored(id: "ts-pr-7078", done: true, content: "#7078 §13 alias APPLY — CLOSED unmerged 2026-07-23 by the namespace lane as premature: dispatched off the design doc's stale import→alias sequencing; the fresh execution receipt shows the flip is a cheap safe substitution that goes first, making the alias tooling premature. Disposition executed; the doc reconcile rides the namespace lane."), authored(id: "ts-pr-7077", done: true, content: "#7077 srv1 deploy readiness fix (was mistitled `dag roadmap work`) — poll bound 30s→120s grounded in measurement: four srv1 starts listening at 35–39s against a 30s bound, so every prior deploy red was the probe quitting ~4s early on a successful start; expectation (40s) and bound (×3 margin) split into separate decls with the demand-scoped-load dissolution trigger — MERGED 2026-07-22 (fec005aa). Residual: `witness_poll_max_attempts_is_thirty` now asserts 120 — rename on next touch."), authored(id: "ts-pr-7076", done: true, content: "#7076 right-size the emitted pre-push hook — CI-scale artifact drift gate dropped from GitPrePushHook — MERGED 2026-07-22 (d50e25b)."), authored(id: "ts-pr-7074", done: true, content: "#7074 cli_run.rs hollowing ledger — CLOSED by operator 2026-07-22, reframed as roadmap description: the census stands as the drain map (867 fns; LensHostBridge 225 + NamespaceResolutionSymbolIndex 214 + AffectedSetSelection 141 = 580/867 — two-thirds of the file on two v2 lanes), while the Python generator and its §3 second-producer question dissolve with the PR. Seed management continues in group 7."), authored(id: "ts-pr-7072", done: true, content: "#7072 finish #7043 floor budget refusal on FloorOutcome + plan-roster fact (`session/tidy-ibex-424`) — MERGED 2026-07-22 (44e538d)."), - authored(id: "ts-pr-7069", done: false, content: "#7069 CI onto v2 — routing frontier + parity gate + consumption P4/P2/R1/R2 (`session/native-routing-consumption`) — operator merging 2026-07-22 after rebase+regen (ci.yml drift collision with the heal merges). Parity windows DEMOTED from flip-precondition to post-flip monitoring (operator re-pricing 2026-07-22: no customers — prefer immediate loud divergence over drip-feed); R2 toolchain-identity key rides its commit 4. Immediate follow-on so it does not pile up: the family re-key row (group 5a); opens the bulk-native arc (group 2a)."), + authored(id: "ts-pr-7069", done: true, content: "#7069 CI onto v2 — routing frontier + parity gate + consumption P4/P2/R1/R2 (`session/native-routing-consumption`) — operator merging 2026-07-22 after rebase+regen (ci.yml drift collision with the heal merges). Parity windows DEMOTED from flip-precondition to post-flip monitoring (operator re-pricing 2026-07-22: no customers — prefer immediate loud divergence over drip-feed); R2 toolchain-identity key rides its commit 4. Immediate follow-on so it does not pile up: the family re-key row (group 5a); opens the bulk-native arc (group 2a)."), authored(id: "ts-pr-7068", done: true, content: "#7068 dissolve cssl_emit_artifact_sanitize v1_rt-strip — dead rule deleted, pub-use-dedupe gap named for crisp-fox-839 — MERGED 2026-07-22 (46127b9)."), - authored(id: "ts-pr-7066", done: false, content: "#7066 Gate-1 receipt lane B1 — modeled per-module behavioral-receipt producer (`session/nimble-deer-372`) — template body; brief pending."), + authored(id: "ts-pr-7066", done: true, content: "#7066 Gate-1 receipt lane B1 — MERGED 2026-07-23: landed as the full per-module behavioral-receipt producer (one roster + one dispatch; 16 hand-authored transports dissolved)."), authored(id: "ts-pr-7058", done: true, content: "#7058 post-merge honest frontier re-sweep — generic-T dead, type-ref-import-missing named successor class (`session/sharp-bee-290-roadmap-converge`) — MERGED 2026-07-22 (e89f076); its main run is the first to exercise the deploy tail with both unit fixes in tree."), authored(id: "ts-pr-7050", done: false, content: "#7050 computation-identity de-fork census R1–R8 (`session/computation-identity-defork`) — doc + bind row only, clean vs main; merge. R2 (durable native cache toolchain identity) now lands via #7069 commit 4 — the census row stays as its receipt."), authored(id: "ts-pr-7027", done: false, content: "#7027 srv4 BMC onboarding G1–G4 — parameterize per-host, gcloud self-provision, operator-token handler (`session/srv4-onboarding-credential-rotation-gap`) — ready; unblocks srv4."), @@ -564,7 +568,7 @@ fn task_sheet_lead_lane() -> RoadmapSection { section_group( label: "Session branches running CI with no open PR at snapshot", nodes: [ - authored(id: "ts-branches", done: false, content: "**each should end as a PR row above or be abandoned deliberately** — `session/sunny-owl-513` (deploy tree-sync fix) · `session/swift-eagle-602` (layering-imports gate P1) · `session/merry-heron-629` (#6985 witness-discovery cascade: pullable() misses arity-zero bare refs) · `session/sleek-crab-621` (fleet_show systemctl via typed extdeps op) · `session/bright-heron-200-work` (exclusion-lane strict-walk closure) · `session/nimble-moth-292-6939` (typed-cache: reference-derived import term in the content key) · `docs/namespace-y-readjudication` (namespace §4 re-adjudication) · `fix/tidy-ibex-merge` (governor fix)."), + authored(id: "ts-branches", done: true, content: "**each should end as a PR row above or be abandoned deliberately** — all 8 dispositioned: 7 merged same-day (#7075 · #7060 · #7061 · #7064 · #7059 · #7062 · #7067); fix/tidy-ibex-merge closed via #7073 as a deliberate duplicate-close of the merged #7072 (both pointed at the identical commit; operator-confirmed 2026-07-23)."), ], edges: [], ), @@ -581,7 +585,7 @@ fn roadmap_authority() -> RoadmapDocument { } fn authored_merged_prs() -> List { - [5873, 6009, 6061, 6097, 6099, 6104, 6106, 6107] + [5873, 6009, 6061, 6097, 6099, 6104, 6106, 6107, 6224, 6479] } fn expected_roadmap_md() -> String { diff --git a/dag/gunbc/roadmap_emit.dag b/dag/gunbc/roadmap_emit.dag index a5d6f63310d..ef488bdc727 100644 --- a/dag/gunbc/roadmap_emit.dag +++ b/dag/gunbc/roadmap_emit.dag @@ -11,12 +11,16 @@ import gunbc.roadmap_model { SectionElement, Prose, Group, SectionProse, SectionGroup, } -import gunbc.roadmap_status { RoadmapItem, DerivableLine, AuthoredLine, PlainLine, item_is_done, signoff_accepts, signoff_by } +import gunbc.roadmap_status { RoadmapItem, DerivableLine, AuthoredLine, PlainLine, SupersededLine, item_is_done, item_superseded_by, signoff_accepts, signoff_by } fn roadmap_max_depth() -> Int { 8 } +fn node_is_superseded(rn: RoadmapNode) -> Bool { + !(item_superseded_by(item: rn.line) == "") +} + fn node_is_done(rn: RoadmapNode, merged: List) -> Bool { - signoff_accepts(s: rn.signoff) + signoff_accepts(s: rn.signoff) || node_is_superseded(rn: rn) } fn node_evidence_present(rn: RoadmapNode, merged: List) -> Bool { @@ -24,13 +28,17 @@ fn node_evidence_present(rn: RoadmapNode, merged: List) -> Bool { } fn signoff_suffix_inlines(rn: RoadmapNode, merged: List) -> List { - if signoff_accepts(s: rn.signoff) { - [TextInline { text: concat(" — ✓ signed off: ", signoff_by(s: rn.signoff)) }] + if node_is_superseded(rn: rn) { + [] } else { - if node_evidence_present(rn: rn, merged: merged) { - [TextInline { text: " — ⏳ awaiting sign-off" }] + if signoff_accepts(s: rn.signoff) { + [TextInline { text: concat(" — ✓ signed off: ", signoff_by(s: rn.signoff)) }] } else { - [] + if node_evidence_present(rn: rn, merged: merged) { + [TextInline { text: " — ⏳ awaiting sign-off" }] + } else { + [] + } } } } @@ -67,6 +75,7 @@ fn line_inlines(line: RoadmapItem) -> List { ) AuthoredLine { done: _, content } => [TextInline { text: content }] PlainLine { content } => [TextInline { text: content }] + SupersededLine { by, content } => [TextInline { text: concat(concat("~~", content), concat("~~ **superseded →** ", by)) }] } } @@ -75,6 +84,7 @@ fn node_is_plain(rn: RoadmapNode) -> Bool { PlainLine { content: _ } => true DerivableLine { prs: _, title: _, description: _ } => false AuthoredLine { done: _, content: _ } => false + SupersededLine { by: _, content: _ } => false } } diff --git a/dag/gunbc/roadmap_page.dag b/dag/gunbc/roadmap_page.dag index 78793a47c59..8151db19214 100644 --- a/dag/gunbc/roadmap_page.dag +++ b/dag/gunbc/roadmap_page.dag @@ -14,7 +14,7 @@ import gunbc.roadmap_model { Intricacy, IntricacyLow, IntricacyMedium, IntricacyHigh, Volume, VolumeSmall, VolumeMedium, VolumeLarge, } -import gunbc.roadmap_status { RoadmapItem, DerivableLine, AuthoredLine, PlainLine, item_is_done, signoff_accepts, signoff_by } +import gunbc.roadmap_status { RoadmapItem, DerivableLine, AuthoredLine, PlainLine, SupersededLine, item_superseded_by, item_is_done, signoff_accepts, signoff_by } import gunbc.roadmap_document { RoadmapDocument, RoadmapSection } import gunbc.roadmap_authority { roadmap_authority, authored_merged_prs } import gunbc.roadmap_spawner { spawn_frontier, SpawnFrontier } @@ -164,14 +164,18 @@ fn el_class(tag: String, cls: String, children: List) -> MarkupNode } fn node_status_symbol(rn: RoadmapNode, merged: List) -> String { - if signoff_accepts(s: rn.signoff) { - "done" - } else { - if item_is_done(item: rn.line, merged: merged) { - "review" + if item_superseded_by(item: rn.line) == "" { + if signoff_accepts(s: rn.signoff) { + "done" } else { - "open" + if item_is_done(item: rn.line, merged: merged) { + "review" + } else { + "open" + } } + } else { + "superseded" } } @@ -204,6 +208,7 @@ fn line_title(line: RoadmapItem) -> String { DerivableLine { prs, title, description } => title AuthoredLine { done, content } => content PlainLine { content } => content + SupersededLine { by: _, content } => content } } @@ -247,10 +252,20 @@ fn sizing_badge(rn: RoadmapNode) -> List { } } +fn superseded_badge(rn: RoadmapNode) -> List { + let by = item_superseded_by(item: rn.line) + if by == "" { + [] + } else { + [ el_class("span", "superseded-by", [ txt(concat("→ ", by)) ]) ] + } +} + data dispatch_button_note: String = "The launch button (roadmap belt A, operator 2026-07-20: manual click-to-dispatch). Rendered on every NOT-signoff-done node (open OR review -- DONE = the operator's signoff, never a merged PR), carrying data-node = the node id. The client script POSTs to /dispatch/NODE and reads belt B's response contract: the `status` member of belt_dispatch_result_json_value, with the ok-set DERIVED from belt_dispatch_ok_status_labels (one authority with the serve JSON -- DESIGN section 3). The retired belt-A `ok`/`node` shape is gone: reading it while B answered `status` made EVERY successful click render 'failed' (found live 2026-07-23; the page witness holds a RED on `j.ok` so the fork cannot silently return). The JS is authored escape-free (no < > &) so it survives std.markup text escaping intact -- the same way roadmap_css() rides inside