diff --git a/.github/live-deploy-srv1-apply.sh b/.github/live-deploy-srv1-apply.sh index b5c5ee93cd5..158c2067205 100644 --- a/.github/live-deploy-srv1-apply.sh +++ b/.github/live-deploy-srv1-apply.sh @@ -115,6 +115,7 @@ Receipts + adjacent levers: [fractal Gantt](docs/plans/ci-floor-fractal-gantt.md - [x] **slice 0 — CI EAGAIN-retry** ✓ (#6467) — \`ci_cargo_eagain_retry_core\` → \`emit(Retry, Bash)\`; byte-oracle = committed \`ci.yml\` [plan](docs/plans/shell-emission-model.md) — ✓ signed off: operator - [x] **slice 1 — control-flow emit (census-scoped)** ✓ (#6475; tier-2 Procedure/Let band #6566) — the \`If\` band only (\`orch_emit_step::If\` + else + condition forms + pipes/cmdsubst/\`\$?\`/AndOr/redirect/env words, byte goldens); \`For\`/\`While\` NOT in scope — the pre-runtime census (2026-07-03) found zero pre-runtime sites needing them [plan](docs/plans/shell-emission-model.md) — ✓ signed off: operator - [ ] **slice 2 — converge thin-run** *(IN FLIGHT 2026-07-14 — FLAGs 2a(i)/2b/2c operator-signed, keystone worker dispatched; [census](docs/plans/shell-to-dag-residual-census-and-arc-completion.md) §2)* — fleet_converge steady-state moves into the binary as a typed plan via \`apply()\` (models \`EmitArtifactThenThinRun\`); emitted bash shrinks to the fresh-standup/self-repair bootstrap fragment + a thin invocation line (supersedes 'emit the whole \`.github/fleet-converge.sh\`') [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. @@ -190,7 +191,7 @@ Every lane below was live roadmap before the reset. Shelved = plan docs and carr - **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 - **design sketches without an active lane** [orchestration-as-intent](docs/plans/orchestration-as-intent-design.md) [model-grounding extract](docs/plans/model-grounding-lens-extract.md) [node-minimal representation](docs/plans/node-minimal-representation-sketch.md) [func-env sigs](docs/plans/func-env-sigs-single-authority.md) [resolved-graph minimization](docs/plans/resolved-graph-representation-minimization.md) [emit-host batch isolation](docs/plans/emit-host-batch-isolation.md) [accelerator roundtrip](docs/plans/accelerator-demo-roundtrip.md) [commit workflow](docs/plans/commit-workflow.md) [input envelope](docs/plans/input-envelope-roadmap.md) [seed-debt bundle 2](docs/plans/seed-debt-bundle-item-2.md) [resolver collision wall](docs/plans/resolver-type-name-collision-wall.md) [regime-2 shared emission](docs/plans/regime2-shared-emission-fold.md) -`, contentType: 'text/plain; charset=utf-8', status: 200 }, { method: 'GET', pathRe: /^\/target\/roadmap-dispatch\.json$/, body: `{"schema": "roadmap-dispatch-file/v1", "brief_template": "Node: \\nWhy now: \\nNon-goals: \\nM0 evidence: \\nM1 smallest change: \\nM2 RED control: \\nM3 green receipt: \\nStop and return if: \\nFiles likely touched: \\nCommands to run: \\nExpected artifact: ", "dispatch": {"schema": "roadmap-dispatch/v1", "ready": [{"node_id": "5-regen-cutover", "title": "**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.", "repo": "gunbc", "intricacy": "medium", "volume": "medium", "parent_node_id": null, "parent_node_ids": [], "owner": null, "plan_doc": null, "acceptance": {"kind": "manual"}}, {"node_id": "5-emit-on-demand", "title": "**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).", "repo": "gunbc", "intricacy": "medium", "volume": "medium", "parent_node_id": null, "parent_node_ids": [], "owner": null, "plan_doc": null, "acceptance": {"kind": "manual"}}, {"node_id": "5-test-migration", "title": "**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.", "repo": "gunbc", "intricacy": "medium", "volume": "large", "parent_node_id": null, "parent_node_ids": [], "owner": null, "plan_doc": null, "acceptance": {"kind": "manual"}}, {"node_id": "2-dispatch-actuator", "title": "**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.", "repo": "gunbc", "intricacy": "high", "volume": "medium", "parent_node_id": null, "parent_node_ids": [], "owner": null, "plan_doc": "docs/plans/dispatch-maintain-cc.md", "acceptance": {"kind": "manual"}}, {"node_id": "2-admission-model", "title": "**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.", "repo": "gunbc", "intricacy": "high", "volume": "medium", "parent_node_id": null, "parent_node_ids": [], "owner": null, "plan_doc": null, "acceptance": {"kind": "manual"}}, {"node_id": "2-stateless-frontend", "title": "**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).", "repo": "gunbc", "intricacy": "high", "volume": "medium", "parent_node_id": "2-cd-transport", "parent_node_ids": ["2-cd-transport"], "owner": null, "plan_doc": null, "acceptance": {"kind": "manual"}}, {"node_id": "2-compile-clean-shard-b", "title": "**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.", "repo": "gunbc", "intricacy": "high", "volume": "medium", "parent_node_id": "2-compile-clean-shard-a", "parent_node_ids": ["2-compile-clean-shard-a"], "owner": null, "plan_doc": null, "acceptance": {"kind": "manual"}}, {"node_id": "1-resolver-pathology-b", "title": "**resolver pathology B — fix one confirmed pathology** — RED control on the pathological pair from the profile receipt, the fix, and a before/after resolve-count or wall-clock receipt.", "repo": "gunbc", "intricacy": "high", "volume": "medium", "parent_node_id": "1-resolver-pathology-a", "parent_node_ids": ["1-resolver-pathology-a"], "owner": null, "plan_doc": null, "acceptance": {"kind": "manual"}}, {"node_id": "2-keyed-delta-fold", "title": "**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.", "repo": "gunbc", "intricacy": "high", "volume": "small", "parent_node_id": null, "parent_node_ids": [], "owner": null, "plan_doc": null, "acceptance": {"kind": "manual"}}, {"node_id": "2-emit-partition", "title": "**emit partition cleanup — shell/json/yaml as grammar rows, zero language knowledge in the wrong layer** *(operator directive, 2026-07-01)* — one grammar per language, read in both directions (DESIGN §4); emission is rows in \`extdeps/languages/\`, never stage code. Four leftovers: (a) \`src/v2/compiler/05_emit_orchestration.dag\` still carries orchestration→bash lowering IN the compiler stage (the retry 2-level expansion, seq-join) — the #6106 registry dispatch is the exit mechanism; the former env-weld half is DISCHARGED (#5868 grew the bash AST \`EnvUnset\` + multi-binding \`EnvPrefixed\`; #6137 dissolved \`orch_emit_run_env_welded\`); the stage keeps ONE agnostic fold. (b) the bash grammar itself is FORKED across trees — \`dag/extdeps/languages/bash/\` vs \`src/v2/extdeps/languages/bash.dag\`+\`bash_command_fold.dag\` — the same §3 class as the \`extdeps.shell\` fork (hotfixed #6112), one authority must win. (c) JSON has no grammar authority: N hand-rolled emitters (\`roadmap_spawner\`'s \`json_escape\`/\`json_str\` is a marked scaffold dissolving to \`std.primitives.to_json\`; \`bmc_onboard\` and \`tailscale_acl_emit\` carry their own). (d) YAML: \`ci_yaml_emit\`/\`ci_yaml_validate\`/\`gha_yaml_fold_pilot\` sit in \`dag/gunbc/\` (workflow layer) while the fold pilot is \`src/v2/extdeps/languages/gha_workflow_yaml_fold.dag\` — YAML-the-language rows belong in \`extdeps/languages/\` with GHA-workflow as rows on top, retiring the \`yaml_check\` Rust scaffold once parse is grammar-owned. The construction wall that makes the splice class unwritable (a string literal is an ATOM, never a COMPOSITION — joins live in \`extdeps/languages\` rows, never workflow code): [no-smuggled-programs wall dissolved with program.dag FULL DELETE — shell → intent design](docs/plans/shell-intent-emit-realization-design.md).", "repo": "gunbc", "intricacy": "high", "volume": "large", "parent_node_id": "2-debash-orchestration", "parent_node_ids": ["2-debash-orchestration"], "owner": "dispatched 2026-07-02 · adhoc-2040cdfe-46b", "plan_doc": null, "acceptance": {"kind": "manual"}}, {"node_id": "2-strictlease", "title": "**StrictLease allocation model (Policy 0)** — every provider exposes strict, non-oversubscribed \`RunShape\` offers first: one allocation consumes its declared RAM/swap/CPU budget, period. srv1/srv2 are modeled like ephemeral providers (N fixed slots, hard cgroup caps, read-back receipts before work); Ubicloud is a provider offer with \`EphemeralVm\` isolation. Burst/oversubscription explicitly out of scope. Four nouns, no scheduler: \`RunShape\` (arch/cpu_tokens/ram/swap/disk/duration/trust/workload_class) · \`ProviderOffer\` (provider/isolation/limits/oversubscription_policy/cost) · \`Allocation\` (shape×offer→target+lease) · \`Receipt\` (effective limits observed, peak usage, pressure/OOM events, release result). **Accept ([checklist](docs/plans/fleet-acceptance-criteria.md)):** one real CI job runs under a \`StrictLease\` allocation on srv1/srv2 whose \`Receipt\` proves effective limits == the offer's declared limits (read back from the live cgroup, never asserted), and a second job requesting more than remaining capacity is refused a lease rather than co-scheduled.", "repo": "gunbc", "intricacy": "high", "volume": "medium", "parent_node_id": null, "parent_node_ids": [], "owner": null, "plan_doc": null, "acceptance": {"kind": "manual"}}, {"node_id": "3-audit-affected-set", "title": "**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.", "repo": "gunbc", "intricacy": "high", "volume": "medium", "parent_node_id": null, "parent_node_ids": [], "owner": null, "plan_doc": null, "acceptance": {"kind": "manual"}}, {"node_id": "3-audit-artifact-freshness", "title": "**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.", "repo": "gunbc", "intricacy": "medium", "volume": "small", "parent_node_id": null, "parent_node_ids": [], "owner": null, "plan_doc": null, "acceptance": {"kind": "manual"}}], "upcoming": [{"node_id": "2-converge-reland", "title": "**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.", "unmet_parents": ["2-live-read-seam", "2-keyed-delta-fold"]}, {"node_id": "2-runner-allocation-v0", "title": "**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.", "unmet_parents": ["2-converge-reland", "2-host-admission"]}, {"node_id": "2-temporal-effect-spine-a", "title": "**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.", "unmet_parents": ["2-host-effect-phases"]}, {"node_id": "2-os-install-deduction-a", "title": "**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.", "unmet_parents": ["2-host-effect-phases"]}, {"node_id": "2-srv3-install-reconcile-a", "title": "**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.", "unmet_parents": ["2-temporal-effect-spine-a", "2-os-install-deduction-a", "2-srv3-osinstalled"]}, {"node_id": "2-resource-namespace-upsert-a", "title": "**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.", "unmet_parents": ["2-srv3-osinstalled"]}, {"node_id": "2-install-media-generic-layer", "title": "**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.", "unmet_parents": ["2-srv3-osinstalled", "2-resource-namespace-upsert-a"]}, {"node_id": "2-nbd-serve-held-session-lease", "title": "**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.", "unmet_parents": ["2-srv3-osinstalled", "2-resource-namespace-upsert-a"]}, {"node_id": "2-srv3-boot-action-diagnostic", "title": "**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.", "unmet_parents": ["2-srv3-osinstalled"]}], "done": ["2-cd-transport", "2-compile-clean-shard-a", "1-resolver-pathology-a", "2-live-read-runner-memory", "2-privilege-model", "3-audit-gate-inventory"]}}`, contentType: 'application/json; charset=utf-8', status: 200 }, { method: 'GET', pathRe: /^\/healthz$/, body: `{"status": "ok", "service": "gunbc-roadmap", "artifacts": {"/ROADMAP.md": "dad423dd541406c2", "/target/roadmap-dispatch.json": "a9e5113e8d73a2bc"}}`, contentType: 'application/json; charset=utf-8', status: 200 }, { method: 'GET', pathRe: /^\/$/, body: `gunbc — roadmap

gunbc — roadmap

0. Priorities — current execution order (rearranged 2026-07-06)

The two pillars — §1 get off v1, §2 own the compute fabric — stand as the strategic goal. This section is the current priority ordering over them and the walls that keep them honest, rearranged 2026-07-06 to frontload the compile wall and complexity enforcement: fix what blocks CI now, then make the regression classes unwritable before they recur (construction over after-the-fact catching, DESIGN §5). Each item points into the detailed lane; work dispatches from the lane, not from the pointer. Lanes marked un-shelved here are moved out of §4 by this ordering.

① Compile wall — the acute blocker. The .dag compile-clean floor runs 100+min (#6239), past the CI job kills, so every PR is red on the floor and the rust-gate timeout thrash (the 10-min-drift #6339 + witness #6342, 2026-07-06) is a downstream symptom of the wall outgrowing the step budgets. Levers, in leverage order: affected-set-scope the compile-clean to the changed node-closure (→ ③), cross-run resolve memoization, per-module shard so spawn_width finally applies to the dominant node. Detail: §2 kill the serial compile-clean wall.

② Complexity enforcement, whole codebase (frontloaded — un-shelved from §4). Make the regression classes unwritable, not caught-after: the repo-wide complexity budget, the enforcement-intent gate (StandingIntent ⇄ LensContract ⇄ CoverageReceipt, fail-closed — a mechanism claiming enforcement is complete only when the gate proves it from receipts), intent-linearity (model the axioms A1–A3 and enforce the syllogism — every claim a consequence-chain back to an axiom, no orphan and no cycle; draft), and the gap analysis — which regression classes cannot be caught yet (the expressibility frontier: wall vs lens vs review; frontier). Detail: §3 enforcement intent + model-quality walls; §4 complexity budget whole-codebase + fail-closed meta band (promoted here).

③ Affected set live in CI — per-PR selection that shrinks the floor to the changed node-closure and returns witness enrollment to affected-set-shrunk discovery (today enrollment is opt-in because selection is not live — itself a compile-wall multiplier). Obligations: soundness (a skipped-but-affected witness is the fail-open catastrophe), effectiveness receipts on real scoped diffs, fail-closed default on a provenance gap. Detail: §2 affected-set de-fork; §3 affected-set lens.

④ Realization — inhabit the content-addressed carrier so caching, memoization, and provisioning all derive from one content-hash instead of N hand-rolled caches (v2 still hand-rolls ParseTable; floor shared-compute memoization is a Realization arm; DESIGN §2). Includes the dag↔v2 de-fork grounding — the fixed point must be well-defined over ONE algebra. Includes execution-as-realization (operator-affirmed 2026-07-07): run ≜ realize ∘ materialize ∘ dependency_view (spine) — interpreted-vs-compiled is a per-node realization policy, not an architecture. The interpreter is the pay-every-run realizer; the emitted native artifact is the pay-once-per-content-hash one, so emit-on-demand (emit closure → build → run, artifact Shared by content-hash) is the canonical execution path for a closed static substrate — no bytecode VM, no JIT (nothing dynamic left to profile; DESIGN §4). The tree-walker's surviving roles (bootstrap S1 receipts · compile-time eval) are bounded scaffolds dissolving with §1 self-hosting. Materialization placement is derived, never hand-added (operator, 2026-07-09 — the state×decision ladder, std.materialization_ladder): demand is read off ONE nested DependencyView — scopes nest eval → plan → process → emitted shell → CI run, a 'run' at any layer being a frame one scope up, never a different kind of thing (every layer is emitted from the same substrate, so the qualifier reaches all of them: it injects a content-hash skip into emitted shell as readily as a Share inside the plan). The law: plurality of demand per identity per frame decides — 0×pure = dead code, 0×effect = the effect is the use, 1 = Recompute, ≥2 with shared-state LCA = authored duplication (ERROR, rewire), ≥2 across isolation = memo obligation at the LCA that MUST be discharged by a covering content-keyed provider with declared eviction (ScopeExit scoped / SpacePacked persistent — dropping pure facts is always sound); declared-emergent frames (retry replay, unbounded siblings: server loops, CI-runs-over-time) obligate UP FRONT — expected emergent redundancy unprepared-for is an error, unexpected emergence is typed acceptance that converts to a declared row next run; an ExistenceKeyed provider is refused (existence ≠ identity — the build-if-absent red, #6352); a redundant WorldRead without a declared staleness envelope is refused (a TTL is a confession: unmodeled dependency or undeclared staleness). Un-shelves §4 caching completion's 'one Materialization kernel'; subsumes ①'s 'cross-run resolve memoization' and §2's 'NOT cross-run caching' into per-node derived verdicts; §3-convergence: v1.compiler.ownership's binding_fan_out is the eval-frame instance (Threaded-excluded plurality; SoleOwner/SharedError), retiring with the seed. Displaced cost already paid: the 9 GB retain-forever resolve store · build-if-absent stale binary · the ~275s double-resolve · the 3× CI release build. Detail: duplicate-work. Detail: §1 de-fork grounding cluster + emit-on-demand execution; §2 shared-compute memoization.

⑤ Everything linear / efficient / minimal — dev UX (un-shelved from §4). The authoring experience is minimal and non-redundant: fold-ergonomics (inert-abstraction lens, non-fold-residue audit, ban source comments), namespace-only resolution (minimal naming, delete import, no ambiguity — operator-signed 2026-07-06, its two rules are the §2/§4 minimality + no-ambiguity walls; gated on the SymbolIndex substrate; design), and local iteration speed. Detail: §4 fold-ergonomics lane (promoted); the namespace-only lane.

1. Get off v1 — v2 self-hosts (TERMINAL: \`src/v1\` deleted)

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 · de-fork audit · seed census

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.

◆ 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

  • openregen-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.i:med v:med gunbc
    • openreal 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.
      • openseed-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
      • openTERMINAL — 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.
  • opendrain 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; 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.
    • reviewno-dual-representation-test lens rebuilt pure-v2
  • openemit-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).i:med v:med gunbc
  • opende-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
    • openRoot B repoints — def-unification (coproduct authority + aliases) → repoints (algebra/nat/integer/float/logic/effects/verification) → 🟡-marker dissolution (keystone #5552 merged)
    • openv1-coupled coercion/node renames — deferred to v1-delete
  • opentest-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.i:med v:large gunbc
  • openemitted 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
  • openmake 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.)

2. Compute fabric — own the infra (CI · deploy · control plane)

State (2026-07-01): required CI is back on the fleet after the Ubicloud detour (#6107, reverted #6111). The detour was the diagnostic and emergency valve, not a failure: it proved raw VM isolation alone does not solve a serial floor (same ~50min wall on both runner types), and it stays the break-glass/burst option, just not the active required path. So the active work is (1) reduce floor recompute, (2) make fleet admission/caps safe — the dominant wall-clock is inside the floor, not host placement alone. The fleet — srv1/srv2 (128c/125GiB Ampere) + srv3 (greenfield, OpenBMC) — carries agent sessions, the dashboard, and all runners, with live cgroup caps, runner registration, sudoers, and tailscale-ACL actuation still hand-managed; the fleet-era OOM/sccache exposure returned with the traffic (operator-accepted interim). #6096 (fleet converge control plane) was closed unmerged; its review gap-list is the re-land spec, and the findings apply to the committed .github/fleet-converge.sh too (mutate-then-read, || true swallowing, no hostname dispatch) — the re-land is an architecture change, not a rebase. → CI humming · host-effect orchestration · compute envelope · charter · host-converge inventory

The core design rule (operator-signed, 2026-07-01): provider-specific power is earned behind a ProviderOffer adapter; the core fabric only knows RunShape → Allocation → Receipt; default allocation is strict/ephemeral; oversubscription is an optimization proven by receipts, never assumed by placement. Not "Ubicloud vs fleet" — GitHub Actions asks for a RunShape, the fabric chooses a ProviderOffer (srv1/srv2 fixed-host slice, Ubicloud ephemeral VM, or later others). srv1/srv2 are modeled as little Ubiclouds first (N strict slots, hard caps, read-back receipts); their richer allocation opportunity (stranded cores, burst, co-residency) is Phase 2, earned by receipts.

◆ Milestones: OOM root-caused (hand-set caps vs measured peaks + budget double-count) ✓ · Ubicloud stabilization trialed ✓ (#6107) → reverted, operator call (#6111 — no wall-clock win; width=9 was live by construction and never touched the serial wall) · converge shell emitted ✓ (#5725/#5827) · apply() Phase A ✓ (#5756) · CD to srv1 ✓ (#6030/#6060/#6093) · witness-level affected-set pruning LIVE ✓ (#6061) → ▸ NOW: kill the serial compile-clean wall · floor <1min · CD wrong-host fix · stateless-frontend MVP (first non-CI fabric consumer) · converge re-land to the signed design → srv1/srv2 runner-allocation v0 (hand-config retired) → StrictLease + shape labels → dormant-Ubicloud provider row (design-break probe) → periodic actuation with receipts → srv3 OsInstalled · apply() Phases B–D → TERMINAL: required CI runs on the compute fabric — the model can choose any admitted ProviderOffer, the receipt proves the shape was honored, and install/manage/decom all ride apply() with fail-closed receipts

Acceptance rule (operator, 2026-07-02): an item is not complete because its algebra exists — it is complete only when a NAMED consumer uses it on the LIVE path and produces a receipt (DESIGN §5: a typecheck or a grep is not a consumer). Completion tiers: T0 modeled · T1 fixture/synthetic witness · T2 wired to the intended consumer (proof by consumption, never grep) · T3 live dry-run receipt · T4 live apply + independent read-back receipt · T5 a periodic/CI consumer keeps it alive. Every dispatchable node states Accept: — its required tier plus an operator-checkable end state on the real fleet (what is different on srv1/srv2 or in CI afterward) plus a discriminating RED; control-plane/fabric items close at T4/T5, and anything below the named tier is a subtask, never completion. A sized node without an explicit Accept is not ready to dispatch; algebra, carriers, and lenses are mechanisms and never their own acceptance. The bar for real progress: can srv1/srv2 runner allocation be changed through the model, read back, re-run safely, and retracted? Until yes, the work is scaffolding. Full per-node checklists: fleet acceptance criteria — the node's Accept line is the summary, the doc is the checklist, and edits to one land with the other.

Now — correctness of the current posture

  • reviewfix 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.@dispatched 2026-07-01 · adhoc-75790c4c-4e0i:high v:small gunbc
    • openstateless 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).i:high v:med gunbc
  • openroadmap 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.i:high v:med gunbcplan
  • openworkload-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.i:high v:med gunbc
  • opencap/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).
  • openmerge-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

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)

  • openkill 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.
    • openaffected-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
      • openprovenance ingest live at floor runtimeplan
      • openhost-scaffold witness classifier de-fork — DONEplan
  • openthe 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).
  • reviewcompile-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.@dispatched 2026-07-01 · adhoc-3e95c046-279i:high v:small gunbc
    • opencompile-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): 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.i:high v:med gunbc
  • openkill 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).
  • doneresolver pathology A — profile receipt only — the 518s resolve: reproducible scripts/profile-cold-resolve.sh; top-N entry offenders; pair budget_roster_completeness_test vs fold_list_generic_instantiation (34.7× cold wall); hypothesis: typecheck_module in reconcile_with_typed_cache.@dispatched 2026-07-01 · adhoc-51b0b8e7-0bei:high v:small gunbc
    • openresolver pathology B — fix one confirmed pathology — RED control on the pathological pair from the profile receipt, the fix, and a before/after resolve-count or wall-clock receipt.i:high v:med gunbc
  • openG5 rust-gate selection — rust fmt/clippy/run-all is all-or-nothing on .rs PRs (the ~530s hot spot); no affected-set, while the .dag floor already has one. Matters until v1 is gone.plan
  • openfloor runs the right things — SELECTION (what changed) vs SCHEDULING (by cost); per-PR = run-all sound baseline (#5427) shrunk to the affected set; cost never drives selection. Scheduling authority: bounded-input / cost-envelope design.plan
  • donebounded-input / cost-envelope scheduling — operator-signed design (2026-07-02 capture) — unified design record: InputEnvelope (data ceiling) → CostEnvelope (symbolic Predicted cost at envelope) → scheduling (width/placement); Predicted authority / Measured falsifier; cost → scheduling never selection. P0 InputEnvelope landed; P1–P5 dispatch separately (no scheduler types in this capture).plan
  • openresolve-cache default-on — purity proven (616/616) but opt-in: whole-file JSON IO buffers ~11× the packed graph and OOMed the concurrent floor (#5789 reverted); gated on a streaming IO realization. The warm ~18% lever, downstream of incrementality.
  • openG4 dispatch dup — workflow_dispatch+PR fire two same-SHA runs; the concurrency fallback won't collapse them → wasted runners and OOM risk (live instance: #6110's draft-attach + ready-flip fired two runs, the cancelled one reporting as a failing check). Superseded runs also linger in_progress for 12–37min — audit cancel-in-progress coverage; leaked runner minutes.decision record

Receipts + adjacent levers: fractal Gantt · memory chronicle · resolver pathology profile · representation minimization · shared-compute memoization (M1 ✓ #6008; M2 gated on determinism #5941) · OOM reclassification · post-engine deferred ledger + algorithm audit · CI-performance tanking evidence — 2026-07-10/11 main-red incident.

Control plane — the #6096 re-land, done right (G2/G3)

  • openG2 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.
  • opensound 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): 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.
  • reviewlive 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.@dispatched 2026-07-01 · adhoc-1e9d7c44-bcci:high v:small gunbc
    • openlive 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): live typed reads on BOTH srv1+srv2 covering the runner units (actions-runner@<host>-*.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.
      • openclosed-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): 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.i:high v:large gunbc
        • openperiodic 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): 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.
        • openrunner 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): 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.i:high v:med gunbc
  • reviewprivilege 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.@dispatched 2026-07-01 · adhoc-3b95241c-d5di:high v:small gunbc
  • openthree-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): (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.i:high v:small gunbc
  • openservice 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): 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.
  • openG3 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.
  • openG1 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
  • openshell emission model — emit(intent, Bash); scoped by the bash-minimization rule (operator 2026-07-03): bash is emitted only into foreign executors + bootstrap windows; where the runtime is present, effects are typed argv/REST or binary-interpreted plans (the tail slices are shelved).plan
    • revieworchestration emission → agnostic registry dispatch
      • openemit partition cleanup — shell/json/yaml as grammar rows, zero language knowledge in the wrong layer (operator directive, 2026-07-01) — one grammar per language, read in both directions (DESIGN §4); emission is rows in extdeps/languages/, never stage code. Four leftovers: (a) src/v2/compiler/05_emit_orchestration.dag still carries orchestration→bash lowering IN the compiler stage (the retry 2-level expansion, seq-join) — the #6106 registry dispatch is the exit mechanism; the former env-weld half is DISCHARGED (#5868 grew the bash AST EnvUnset + multi-binding EnvPrefixed; #6137 dissolved orch_emit_run_env_welded); the stage keeps ONE agnostic fold. (b) the bash grammar itself is FORKED across trees — dag/extdeps/languages/bash/ vs src/v2/extdeps/languages/bash.dag+bash_command_fold.dag — the same §3 class as the extdeps.shell fork (hotfixed #6112), one authority must win. (c) JSON has no grammar authority: N hand-rolled emitters (roadmap_spawner's json_escape/json_str is a marked scaffold dissolving to std.primitives.to_json; bmc_onboard and tailscale_acl_emit carry their own). (d) YAML: ci_yaml_emit/ci_yaml_validate/gha_yaml_fold_pilot sit in dag/gunbc/ (workflow layer) while the fold pilot is src/v2/extdeps/languages/gha_workflow_yaml_fold.dag — YAML-the-language rows belong in extdeps/languages/ with GHA-workflow as rows on top, retiring the yaml_check Rust scaffold once parse is grammar-owned. The construction wall that makes the splice class unwritable (a string literal is an ATOM, never a COMPOSITION — joins live in extdeps/languages rows, never workflow code): no-smuggled-programs wall dissolved with program.dag FULL DELETE — shell → intent design.@dispatched 2026-07-02 · adhoc-2040cdfe-46bi:high v:large gunbc
    • doneslice 0 — CI EAGAIN-retry ✓ (#6467) — ci_cargo_eagain_retry_core → emit(Retry, Bash); byte-oracle = committed ci.ymlplan
      • doneslice 1 — control-flow emit (census-scoped) ✓ (#6475; tier-2 Procedure/Let band #6566) — the If band only (orch_emit_step::If + else + condition forms + pipes/cmdsubst/\$?/AndOr/redirect/env words, byte goldens); For/While NOT in scope — the pre-runtime census (2026-07-03) found zero pre-runtime sites needing themplan
        • openslice 2 — converge thin-run (IN FLIGHT 2026-07-14 — FLAGs 2a(i)/2b/2c operator-signed, keystone worker dispatched; census §2) — fleet_converge steady-state moves into the binary as a typed plan via apply() (models EmitArtifactThenThinRun); emitted bash shrinks to the fresh-standup/self-repair bootstrap fragment + a thin invocation line (supersedes 'emit the whole .github/fleet-converge.sh')plan
  • openapply() 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
    • opentemporal-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.@dispatched 2026-07-02 · zesty-bat-588i:high v:small gunbc
      • opensrv3-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.i:high v:med gunbc
    • openos-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.@dispatched 2026-07-02 · zesty-bat-588i:high v:small gunbc
  • opensrv3 → OsInstalled — finish the greenfield install over the solve-driven NBD-proxy actuator (#6097, live BMC); proves the install band end-to-end.plan
    • openresource-namespace-upsert-a — vocabulary only (#6134 srv3 bringup follow-up; operator reshape 2026-07-03) — std.upsert_decision (ObservationVerdict + UpsertDecision<P>); 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.i:high v:small gunbc
    • openinstall-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.i:high v:med gunbc
    • opennbd-serve-held-session-lease — NbdProxyServeSession intent with port/pid/cmdline/ISO/token fingerprint; classification + plan INSTANTIATE std.upsert_decision (ObservationVerdict + UpsertDecision<P>; 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.i:high v:med gunbc
    • opensrv3-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.i:high v:small gunbc
    • openos-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.

Fabric dispatch — RunShape → Allocation → Receipt (GitHub is the queue, not the scheduler)

  • openStrictLease allocation model (Policy 0) — every provider exposes strict, non-oversubscribed RunShape offers first: one allocation consumes its declared RAM/swap/CPU budget, period. srv1/srv2 are modeled like ephemeral providers (N fixed slots, hard cgroup caps, read-back receipts before work); Ubicloud is a provider offer with EphemeralVm isolation. Burst/oversubscription explicitly out of scope. Four nouns, no scheduler: RunShape (arch/cpu_tokens/ram/swap/disk/duration/trust/workload_class) · ProviderOffer (provider/isolation/limits/oversubscription_policy/cost) · Allocation (shape×offer→target+lease) · Receipt (effective limits observed, peak usage, pressure/OOM events, release result). Accept (checklist): one real CI job runs under a StrictLease allocation on srv1/srv2 whose Receipt proves effective limits == the offer's declared limits (read back from the live cgroup, never asserted), and a second job requesting more than remaining capacity is refused a lease rather than co-scheduled.i:high v:med gunbc
    • openCI shape labels — runs-on as a projection of the fabric model — ci.yml emits runs-on labels derived from RunShape (e.g. gunbc-shape-ci-42c-128g), never host names; the runner registration/converge layer ensures the right runners carry those labels. GitHub remains the queue and runner availability is the backpressure: register slots per shape at safe strict capacity (e.g. 2 shape-rust-heavy + more light), NOT 10 equivalent heavy runners when only 2 heavy jobs are safe. A fabric-control-plane allocator (a .dag control server minting leases/JIT runners before dispatch) is the LATER architecture — only after srv1/srv2 are safely mutable and readable.
    • openProviderOffer rows + the dormant-Ubicloud design-break probe — srv1/srv2 fixed-host slots and Ubicloud ephemeral VMs inhabit the same offer type; add the Ubicloud row Dormant (16 vCPU/48GiB arm64, oversubscription: None) without running it. Acceptance = adding the offer changes no scheduler/control-plane invariant: witnesses prove (a) allocation accepts both SrvHostSlot and UbicloudVmOffer, (b) host-mutation code REFUSES Ubicloud offers (no cgroup target to mutate), (c) deploy-to-srv1 refuses LocalShell unless the allocation target proves host=srv1, (d) emitted labels encode shape, not provider host details. If adding Ubicloud forces a special case anywhere, the abstraction is wrong — this probe answers "does our design break?" before it can cost anything.
      • openBurstLease (Policy 1) — oversubscription earned by receipts — co-resident allocations on one host only after pressure/OOM/swap receipts prove the measured peaks allow it; StrictLease stays the default and the fallback. This is where stranded cores come back (sessions, compression, IO, smaller jobs) — on 128c/125GiB, strict memory allocation strands CPU and that is correct: the first goal is non-death, not full utilization. Gated on the sound-host-admission receipts and the live read seam.

Ordering (operator-signed): ① CD target-host proof → ② stateless-frontend MVP receipt (milestone A, on the existing deploy path) → ③ live read seam + privilege model → ④ one converge hunk closed-loop end-to-end (the narrow srv2 acceptance case) → ⑤ service allocation generalized from the frontend MVP → ⑥ StrictLease + shape labels; register srv1/srv2 slots by shape → ⑦ dormant Ubicloud row proves no design break → ⑧ CI jobs move to shape labels → ⑨ receipts (effective limits · peaks · OOM/swap pressure) → ⑩ BurstLease / dynamic routing / richer placement. ①–④ make infra changeable (everything else is paper until then); ⑤ proves the fabric is not just CI; ⑥ fixes backpressure with no scheduler; ⑦ validates the abstraction before we depend on it; ⑧–⑨ make CI consume the model; ⑩ recovers stranded cores.

Fleet hardening — make our metal safe for the load it carries

  • openthe 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).
    • openSessionSliceEnforcement + 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.
    • openOOM 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
  • openresource-aware scheduler (implementation) — implements the signed bounded-input / cost-envelope scheduling 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
  • openresource 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).carriergrounding
  • openone 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.

3. The floor — audit what we have (does it actually do what it claims?)

Both pillars ride the CI floor: tree-wide marker-driven witness discovery · compile-clean gate · generated-artifact drift gates (this document is one) · regen --verify (#5873) · doc-graph reachability · emit-determinism (#5941) · the interim self-host comparison (#6009). Those stand. The floor's expansion lanes (testgen, wiring-liveness, complexity gates, lens meta-walls) are shelved — a new wall must displace a measured cost on a pillar path to un-shelve (the enforcement-intent gate below is the first such un-shelve, 2026-07-02: displaced cost = the operator's repeated manual what-is-enforced-by-what-lens-over-what-corpus join, plus CI-killing quadratics and repeated dual-representation/anemia rediscovery).

Audit directive (operator, 2026-07-01): thoroughly audit what we have and what it actually does. For each load-bearing mechanism, prove by execution that it does what it claims, with a discriminating perturb that goes RED when the behavior is wrong — a typecheck or a grep is not a consumer (DESIGN §5), and a wired gate can still be vacuous. A mechanism claim without a red-control is unverified, whatever its docs say. The reset's own mapping found the pattern live: the committed converge shell is spec-without-execution (§2), the fixpoint gate self-declares interim (2-of-92 files), cargo-green is an ignored test. Highest-stakes mechanisms first:

Audit — green by execution, red by perturbation

  • openaffected-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.i:high v:med gunbc
  • donemechanism 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.@dispatched 2026-07-01 · adhoc-c67edbed-916i:med v:large gunbcplan
  • opencache 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.
  • openartifact-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.i:med v:small gunbc
  • openone 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.
  • openenforcement 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 CoverageReceipts) · 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

Cost / risk / benefit — the floor's unmodeled optimization

  • openmodel cost/risk/benefit — "what do we actually run" is one optimization, not a pile of policies (operator working session 2026-07-12) — affected-set, wet/dry (mocks), receipt/long, ReadsLiveTree never-skip, and the test-kind names (test/receipt/demo/integration, WitnessKind, TestClassification) are all unmodeled proxies for argmax(benefit − cost) under a budget — hand-tuned stand-ins (mostly astrology) that exist because cost/risk/benefit were never first-class. Root anemia: test fn bakes in cost ≈ 0, run always, which is false (s1_closure ≈ 10min wet). Invariant that keeps it fail-closed: you may trade fidelity for cost (mocks, skips, deferrals), but the risk you trade away must stay observable on a cadence — deferred-and-detected, never silent (§5; a silent widen is the absorbing fallback). This inverts the tree's current wet-is-sacred default: wet is just the highest-cost fidelity point, usually not worth it. Bootstrappable now: a claim's expected internal work is inspectable (inputs/expected-output node shape) and its effects enumerable (which service ops, how many times via fold/loop bounds), each effect carrying a latency expectation; the floor already MEASURES wall_nanos/cgroup-peak per claim, so cost = measured receipt now → graph-derived later (§4). Landed as approximation in #6506 (Stages 0–2): hermetic-by-default floor, a flat hand-set 5s per-witness budget (fail-closed EvalBudgetExceeded), and a test/claim/long/ cadence — right shape, interim stand-ins; forward work is Stages 3–5. Missing pieces (highlighted, not papered over): no per-effect cost model; cost only bounded by the flat 5s budget, not derived from the graph (fail-closed = expensive on unknown fold bounds); the budget is flat/hand-set, not a per-run wall-clock allocated by value/cost; benefit unmodeled — only footholds are the §5 lower bound (no discriminating red ⟹ ~0 gate-value ⟹ drop, this is what a pure demo is) and observed red-frequency; the proxies aren't yet reconciled to the axes. Sequence: cost first (compute/resources, from what's measurable now) with budget-aware admission and counted typed deferrals (never silent skip) → benefit second (§5 lower bound + red-frequency, declared interim for the rest) → then affected-set/wet-dry/cadence/test-kinds collapse into derived readings and the qualitative vocabulary is deleted, not extended.cost/risk/benefit model

Open floor holes

  • opennightly full-corpus selector-backstop — per-PR selection is only sound because nightly runs everything; ⚠ CI-gen load-bearing
  • opentree-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) openforce-check plan
  • openkill sccache false-greens — exit-0-no-binary; build-verify asserts the artifact exists + is fresh (partly landed in ci.yml)

4. Shelved (parked 2026-07-01 — not deleted)

Every lane below was live roadmap before the reset. Shelved = plan docs and carriers stay in place, nothing dispatches from here, and the git-history ROADMAP.md holds the full pre-reset detail (structure, milestones, sign-off states). Un-shelve by PR into §1–§3, priced in displaced cost. (2026-07-06: the complexity budget whole-codebase, fail-closed meta band, and fold-ergonomics lanes are un-shelved into §0's priority order ② and ⑤ — this reshuffle is that PR; their nodes stay catalogued here until relocated into their §2/§3 lanes.)

  • openfold-ergonomics lane — inert-abstraction lens · non-fold-residue audit · staging combinator · ban source comments charter residue catalogue debt sample audit eval-bind PROPOSE
  • openfail-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 fork plan Disposition reference grounding cardinality P1 where-lowering frontier inert-layer lens axiom lens self-applying construction rule
  • openrust-gate .dag→rust coverage wall (edge-b) + stage0 clone-census ratchet brief
  • opencomplexity budget whole-codebase + the algebraic-rewrite construction engine (O(n²)→O(n) catalog, Unknown dissolution) rewrite plan
  • opentestgen oracle + wiring-liveness family (compile-time wiring lens ✓ #5679 · pre-send guard ✓ #5683 stand; the generator/preflight expansion parks) method wiring
  • opencaching 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 M4 M5
  • openCI inline-shell de-fork · interpreter terminal-output de-fork (seed forks of modeled authorities; both shrink as v1 burns down) emission-ingestion
  • openidea 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 format reconciliation invert
  • openshell-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
  • openTypeScript first-class emit + TS self-host — END GOAL UNCHANGED (both realizations, per plan do-not-relitigate); resumes after the Rust fixed point gap census
  • openlanguage-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 solve rationale
  • openHTML/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)
  • opensession 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
  • opengunbhub (own the Git/CI engine, closes G6) · internal repo model · compute fabric as a sellable piece
  • openprivacy / 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.
  • openstructural 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
  • opendesign sketches without an active lane orchestration-as-intent model-grounding extract node-minimal representation func-env sigs resolved-graph minimization emit-host batch isolation accelerator roundtrip commit workflow input envelope seed-debt bundle 2 resolver collision wall regime-2 shared emission
`, contentType: 'text/html; charset=utf-8', status: 200 }]; +.frontier-done h2 { color: #0a3622 }gunbc — roadmap

gunbc — roadmap

0. Priorities — current execution order (rearranged 2026-07-06)

The two pillars — §1 get off v1, §2 own the compute fabric — stand as the strategic goal. This section is the current priority ordering over them and the walls that keep them honest, rearranged 2026-07-06 to frontload the compile wall and complexity enforcement: fix what blocks CI now, then make the regression classes unwritable before they recur (construction over after-the-fact catching, DESIGN §5). Each item points into the detailed lane; work dispatches from the lane, not from the pointer. Lanes marked un-shelved here are moved out of §4 by this ordering.

① Compile wall — the acute blocker. The .dag compile-clean floor runs 100+min (#6239), past the CI job kills, so every PR is red on the floor and the rust-gate timeout thrash (the 10-min-drift #6339 + witness #6342, 2026-07-06) is a downstream symptom of the wall outgrowing the step budgets. Levers, in leverage order: affected-set-scope the compile-clean to the changed node-closure (→ ③), cross-run resolve memoization, per-module shard so spawn_width finally applies to the dominant node. Detail: §2 kill the serial compile-clean wall.

② Complexity enforcement, whole codebase (frontloaded — un-shelved from §4). Make the regression classes unwritable, not caught-after: the repo-wide complexity budget, the enforcement-intent gate (StandingIntent ⇄ LensContract ⇄ CoverageReceipt, fail-closed — a mechanism claiming enforcement is complete only when the gate proves it from receipts), intent-linearity (model the axioms A1–A3 and enforce the syllogism — every claim a consequence-chain back to an axiom, no orphan and no cycle; draft), and the gap analysis — which regression classes cannot be caught yet (the expressibility frontier: wall vs lens vs review; frontier). Detail: §3 enforcement intent + model-quality walls; §4 complexity budget whole-codebase + fail-closed meta band (promoted here).

③ Affected set live in CI — per-PR selection that shrinks the floor to the changed node-closure and returns witness enrollment to affected-set-shrunk discovery (today enrollment is opt-in because selection is not live — itself a compile-wall multiplier). Obligations: soundness (a skipped-but-affected witness is the fail-open catastrophe), effectiveness receipts on real scoped diffs, fail-closed default on a provenance gap. Detail: §2 affected-set de-fork; §3 affected-set lens.

④ Realization — inhabit the content-addressed carrier so caching, memoization, and provisioning all derive from one content-hash instead of N hand-rolled caches (v2 still hand-rolls ParseTable; floor shared-compute memoization is a Realization arm; DESIGN §2). Includes the dag↔v2 de-fork grounding — the fixed point must be well-defined over ONE algebra. Includes execution-as-realization (operator-affirmed 2026-07-07): run ≜ realize ∘ materialize ∘ dependency_view (spine) — interpreted-vs-compiled is a per-node realization policy, not an architecture. The interpreter is the pay-every-run realizer; the emitted native artifact is the pay-once-per-content-hash one, so emit-on-demand (emit closure → build → run, artifact Shared by content-hash) is the canonical execution path for a closed static substrate — no bytecode VM, no JIT (nothing dynamic left to profile; DESIGN §4). The tree-walker's surviving roles (bootstrap S1 receipts · compile-time eval) are bounded scaffolds dissolving with §1 self-hosting. Materialization placement is derived, never hand-added (operator, 2026-07-09 — the state×decision ladder, std.materialization_ladder): demand is read off ONE nested DependencyView — scopes nest eval → plan → process → emitted shell → CI run, a 'run' at any layer being a frame one scope up, never a different kind of thing (every layer is emitted from the same substrate, so the qualifier reaches all of them: it injects a content-hash skip into emitted shell as readily as a Share inside the plan). The law: plurality of demand per identity per frame decides — 0×pure = dead code, 0×effect = the effect is the use, 1 = Recompute, ≥2 with shared-state LCA = authored duplication (ERROR, rewire), ≥2 across isolation = memo obligation at the LCA that MUST be discharged by a covering content-keyed provider with declared eviction (ScopeExit scoped / SpacePacked persistent — dropping pure facts is always sound); declared-emergent frames (retry replay, unbounded siblings: server loops, CI-runs-over-time) obligate UP FRONT — expected emergent redundancy unprepared-for is an error, unexpected emergence is typed acceptance that converts to a declared row next run; an ExistenceKeyed provider is refused (existence ≠ identity — the build-if-absent red, #6352); a redundant WorldRead without a declared staleness envelope is refused (a TTL is a confession: unmodeled dependency or undeclared staleness). Un-shelves §4 caching completion's 'one Materialization kernel'; subsumes ①'s 'cross-run resolve memoization' and §2's 'NOT cross-run caching' into per-node derived verdicts; §3-convergence: v1.compiler.ownership's binding_fan_out is the eval-frame instance (Threaded-excluded plurality; SoleOwner/SharedError), retiring with the seed. Displaced cost already paid: the 9 GB retain-forever resolve store · build-if-absent stale binary · the ~275s double-resolve · the 3× CI release build. Detail: duplicate-work. Detail: §1 de-fork grounding cluster + emit-on-demand execution; §2 shared-compute memoization.

⑤ Everything linear / efficient / minimal — dev UX (un-shelved from §4). The authoring experience is minimal and non-redundant: fold-ergonomics (inert-abstraction lens, non-fold-residue audit, ban source comments), namespace-only resolution (minimal naming, delete import, no ambiguity — operator-signed 2026-07-06, its two rules are the §2/§4 minimality + no-ambiguity walls; gated on the SymbolIndex substrate; design), and local iteration speed. Detail: §4 fold-ergonomics lane (promoted); the namespace-only lane.

1. Get off v1 — v2 self-hosts (TERMINAL: \`src/v1\` deleted)

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 · de-fork audit · seed census

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.

◆ 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

  • openregen-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.i:med v:med gunbc
    • openreal 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.
      • openseed-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
      • openTERMINAL — 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.
  • opendrain 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; 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.
    • reviewno-dual-representation-test lens rebuilt pure-v2
  • openemit-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).i:med v:med gunbc
  • opende-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
    • openRoot B repoints — def-unification (coproduct authority + aliases) → repoints (algebra/nat/integer/float/logic/effects/verification) → 🟡-marker dissolution (keystone #5552 merged)
    • openv1-coupled coercion/node renames — deferred to v1-delete
  • opentest-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.i:med v:large gunbc
  • openemitted 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
  • openmake 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.)

2. Compute fabric — own the infra (CI · deploy · control plane)

State (2026-07-01): required CI is back on the fleet after the Ubicloud detour (#6107, reverted #6111). The detour was the diagnostic and emergency valve, not a failure: it proved raw VM isolation alone does not solve a serial floor (same ~50min wall on both runner types), and it stays the break-glass/burst option, just not the active required path. So the active work is (1) reduce floor recompute, (2) make fleet admission/caps safe — the dominant wall-clock is inside the floor, not host placement alone. The fleet — srv1/srv2 (128c/125GiB Ampere) + srv3 (greenfield, OpenBMC) — carries agent sessions, the dashboard, and all runners, with live cgroup caps, runner registration, sudoers, and tailscale-ACL actuation still hand-managed; the fleet-era OOM/sccache exposure returned with the traffic (operator-accepted interim). #6096 (fleet converge control plane) was closed unmerged; its review gap-list is the re-land spec, and the findings apply to the committed .github/fleet-converge.sh too (mutate-then-read, || true swallowing, no hostname dispatch) — the re-land is an architecture change, not a rebase. → CI humming · host-effect orchestration · compute envelope · charter · host-converge inventory

The core design rule (operator-signed, 2026-07-01): provider-specific power is earned behind a ProviderOffer adapter; the core fabric only knows RunShape → Allocation → Receipt; default allocation is strict/ephemeral; oversubscription is an optimization proven by receipts, never assumed by placement. Not "Ubicloud vs fleet" — GitHub Actions asks for a RunShape, the fabric chooses a ProviderOffer (srv1/srv2 fixed-host slice, Ubicloud ephemeral VM, or later others). srv1/srv2 are modeled as little Ubiclouds first (N strict slots, hard caps, read-back receipts); their richer allocation opportunity (stranded cores, burst, co-residency) is Phase 2, earned by receipts.

◆ Milestones: OOM root-caused (hand-set caps vs measured peaks + budget double-count) ✓ · Ubicloud stabilization trialed ✓ (#6107) → reverted, operator call (#6111 — no wall-clock win; width=9 was live by construction and never touched the serial wall) · converge shell emitted ✓ (#5725/#5827) · apply() Phase A ✓ (#5756) · CD to srv1 ✓ (#6030/#6060/#6093) · witness-level affected-set pruning LIVE ✓ (#6061) → ▸ NOW: kill the serial compile-clean wall · floor <1min · CD wrong-host fix · stateless-frontend MVP (first non-CI fabric consumer) · converge re-land to the signed design → srv1/srv2 runner-allocation v0 (hand-config retired) → StrictLease + shape labels → dormant-Ubicloud provider row (design-break probe) → periodic actuation with receipts → srv3 OsInstalled · apply() Phases B–D → TERMINAL: required CI runs on the compute fabric — the model can choose any admitted ProviderOffer, the receipt proves the shape was honored, and install/manage/decom all ride apply() with fail-closed receipts

Acceptance rule (operator, 2026-07-02): an item is not complete because its algebra exists — it is complete only when a NAMED consumer uses it on the LIVE path and produces a receipt (DESIGN §5: a typecheck or a grep is not a consumer). Completion tiers: T0 modeled · T1 fixture/synthetic witness · T2 wired to the intended consumer (proof by consumption, never grep) · T3 live dry-run receipt · T4 live apply + independent read-back receipt · T5 a periodic/CI consumer keeps it alive. Every dispatchable node states Accept: — its required tier plus an operator-checkable end state on the real fleet (what is different on srv1/srv2 or in CI afterward) plus a discriminating RED; control-plane/fabric items close at T4/T5, and anything below the named tier is a subtask, never completion. A sized node without an explicit Accept is not ready to dispatch; algebra, carriers, and lenses are mechanisms and never their own acceptance. The bar for real progress: can srv1/srv2 runner allocation be changed through the model, read back, re-run safely, and retracted? Until yes, the work is scaffolding. Full per-node checklists: fleet acceptance criteria — the node's Accept line is the summary, the doc is the checklist, and edits to one land with the other.

Now — correctness of the current posture

  • reviewfix 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.@dispatched 2026-07-01 · adhoc-75790c4c-4e0i:high v:small gunbc
    • openstateless 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).i:high v:med gunbc
  • openroadmap 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.i:high v:med gunbcplan
  • openworkload-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.i:high v:med gunbc
  • opencap/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).
  • openmerge-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

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)

  • openkill 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.
    • openaffected-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
      • openprovenance ingest live at floor runtimeplan
      • openhost-scaffold witness classifier de-fork — DONEplan
  • openthe 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).
  • reviewcompile-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.@dispatched 2026-07-01 · adhoc-3e95c046-279i:high v:small gunbc
    • opencompile-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): 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.i:high v:med gunbc
  • openkill 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).
  • doneresolver pathology A — profile receipt only — the 518s resolve: reproducible scripts/profile-cold-resolve.sh; top-N entry offenders; pair budget_roster_completeness_test vs fold_list_generic_instantiation (34.7× cold wall); hypothesis: typecheck_module in reconcile_with_typed_cache.@dispatched 2026-07-01 · adhoc-51b0b8e7-0bei:high v:small gunbc
    • openresolver pathology B — fix one confirmed pathology — RED control on the pathological pair from the profile receipt, the fix, and a before/after resolve-count or wall-clock receipt.i:high v:med gunbc
  • openG5 rust-gate selection — rust fmt/clippy/run-all is all-or-nothing on .rs PRs (the ~530s hot spot); no affected-set, while the .dag floor already has one. Matters until v1 is gone.plan
  • openfloor runs the right things — SELECTION (what changed) vs SCHEDULING (by cost); per-PR = run-all sound baseline (#5427) shrunk to the affected set; cost never drives selection. Scheduling authority: bounded-input / cost-envelope design.plan
  • donebounded-input / cost-envelope scheduling — operator-signed design (2026-07-02 capture) — unified design record: InputEnvelope (data ceiling) → CostEnvelope (symbolic Predicted cost at envelope) → scheduling (width/placement); Predicted authority / Measured falsifier; cost → scheduling never selection. P0 InputEnvelope landed; P1–P5 dispatch separately (no scheduler types in this capture).plan
  • openresolve-cache default-on — purity proven (616/616) but opt-in: whole-file JSON IO buffers ~11× the packed graph and OOMed the concurrent floor (#5789 reverted); gated on a streaming IO realization. The warm ~18% lever, downstream of incrementality.
  • openG4 dispatch dup — workflow_dispatch+PR fire two same-SHA runs; the concurrency fallback won't collapse them → wasted runners and OOM risk (live instance: #6110's draft-attach + ready-flip fired two runs, the cancelled one reporting as a failing check). Superseded runs also linger in_progress for 12–37min — audit cancel-in-progress coverage; leaked runner minutes.decision record

Receipts + adjacent levers: fractal Gantt · memory chronicle · resolver pathology profile · representation minimization · shared-compute memoization (M1 ✓ #6008; M2 gated on determinism #5941) · OOM reclassification · post-engine deferred ledger + algorithm audit · CI-performance tanking evidence — 2026-07-10/11 main-red incident.

Control plane — the #6096 re-land, done right (G2/G3)

  • openG2 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.
  • opensound 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): 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.
  • reviewlive 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.@dispatched 2026-07-01 · adhoc-1e9d7c44-bcci:high v:small gunbc
    • openlive 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): live typed reads on BOTH srv1+srv2 covering the runner units (actions-runner@<host>-*.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.
      • openclosed-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): 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.i:high v:large gunbc
        • openperiodic 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): 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.
        • openrunner 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): 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.i:high v:med gunbc
  • reviewprivilege 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.@dispatched 2026-07-01 · adhoc-3b95241c-d5di:high v:small gunbc
  • openthree-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): (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.i:high v:small gunbc
  • openservice 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): 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.
  • openG3 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.
  • openG1 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
  • openshell emission model — emit(intent, Bash); scoped by the bash-minimization rule (operator 2026-07-03): bash is emitted only into foreign executors + bootstrap windows; where the runtime is present, effects are typed argv/REST or binary-interpreted plans (the tail slices are shelved).plan
    • revieworchestration emission → agnostic registry dispatch
      • openemit partition cleanup — shell/json/yaml as grammar rows, zero language knowledge in the wrong layer (operator directive, 2026-07-01) — one grammar per language, read in both directions (DESIGN §4); emission is rows in extdeps/languages/, never stage code. Four leftovers: (a) src/v2/compiler/05_emit_orchestration.dag still carries orchestration→bash lowering IN the compiler stage (the retry 2-level expansion, seq-join) — the #6106 registry dispatch is the exit mechanism; the former env-weld half is DISCHARGED (#5868 grew the bash AST EnvUnset + multi-binding EnvPrefixed; #6137 dissolved orch_emit_run_env_welded); the stage keeps ONE agnostic fold. (b) the bash grammar itself is FORKED across trees — dag/extdeps/languages/bash/ vs src/v2/extdeps/languages/bash.dag+bash_command_fold.dag — the same §3 class as the extdeps.shell fork (hotfixed #6112), one authority must win. (c) JSON has no grammar authority: N hand-rolled emitters (roadmap_spawner's json_escape/json_str is a marked scaffold dissolving to std.primitives.to_json; bmc_onboard and tailscale_acl_emit carry their own). (d) YAML: ci_yaml_emit/ci_yaml_validate/gha_yaml_fold_pilot sit in dag/gunbc/ (workflow layer) while the fold pilot is src/v2/extdeps/languages/gha_workflow_yaml_fold.dag — YAML-the-language rows belong in extdeps/languages/ with GHA-workflow as rows on top, retiring the yaml_check Rust scaffold once parse is grammar-owned. The construction wall that makes the splice class unwritable (a string literal is an ATOM, never a COMPOSITION — joins live in extdeps/languages rows, never workflow code): no-smuggled-programs wall dissolved with program.dag FULL DELETE — shell → intent design.@dispatched 2026-07-02 · adhoc-2040cdfe-46bi:high v:large gunbc
    • doneslice 0 — CI EAGAIN-retry ✓ (#6467) — ci_cargo_eagain_retry_core → emit(Retry, Bash); byte-oracle = committed ci.ymlplan
      • doneslice 1 — control-flow emit (census-scoped) ✓ (#6475; tier-2 Procedure/Let band #6566) — the If band only (orch_emit_step::If + else + condition forms + pipes/cmdsubst/\$?/AndOr/redirect/env words, byte goldens); For/While NOT in scope — the pre-runtime census (2026-07-03) found zero pre-runtime sites needing themplan
        • openslice 2 — converge thin-run (IN FLIGHT 2026-07-14 — FLAGs 2a(i)/2b/2c operator-signed, keystone worker dispatched; census §2) — fleet_converge steady-state moves into the binary as a typed plan via apply() (models EmitArtifactThenThinRun); emitted bash shrinks to the fresh-standup/self-repair bootstrap fragment + a thin invocation line (supersedes 'emit the whole .github/fleet-converge.sh')plan
    • openshell→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
  • openapply() 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
    • opentemporal-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.@dispatched 2026-07-02 · zesty-bat-588i:high v:small gunbc
      • opensrv3-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.i:high v:med gunbc
    • openos-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.@dispatched 2026-07-02 · zesty-bat-588i:high v:small gunbc
  • opensrv3 → OsInstalled — finish the greenfield install over the solve-driven NBD-proxy actuator (#6097, live BMC); proves the install band end-to-end.plan
    • openresource-namespace-upsert-a — vocabulary only (#6134 srv3 bringup follow-up; operator reshape 2026-07-03) — std.upsert_decision (ObservationVerdict + UpsertDecision<P>); 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.i:high v:small gunbc
    • openinstall-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.i:high v:med gunbc
    • opennbd-serve-held-session-lease — NbdProxyServeSession intent with port/pid/cmdline/ISO/token fingerprint; classification + plan INSTANTIATE std.upsert_decision (ObservationVerdict + UpsertDecision<P>; 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.i:high v:med gunbc
    • opensrv3-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.i:high v:small gunbc
    • openos-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.

Fabric dispatch — RunShape → Allocation → Receipt (GitHub is the queue, not the scheduler)

  • openStrictLease allocation model (Policy 0) — every provider exposes strict, non-oversubscribed RunShape offers first: one allocation consumes its declared RAM/swap/CPU budget, period. srv1/srv2 are modeled like ephemeral providers (N fixed slots, hard cgroup caps, read-back receipts before work); Ubicloud is a provider offer with EphemeralVm isolation. Burst/oversubscription explicitly out of scope. Four nouns, no scheduler: RunShape (arch/cpu_tokens/ram/swap/disk/duration/trust/workload_class) · ProviderOffer (provider/isolation/limits/oversubscription_policy/cost) · Allocation (shape×offer→target+lease) · Receipt (effective limits observed, peak usage, pressure/OOM events, release result). Accept (checklist): one real CI job runs under a StrictLease allocation on srv1/srv2 whose Receipt proves effective limits == the offer's declared limits (read back from the live cgroup, never asserted), and a second job requesting more than remaining capacity is refused a lease rather than co-scheduled.i:high v:med gunbc
    • openCI shape labels — runs-on as a projection of the fabric model — ci.yml emits runs-on labels derived from RunShape (e.g. gunbc-shape-ci-42c-128g), never host names; the runner registration/converge layer ensures the right runners carry those labels. GitHub remains the queue and runner availability is the backpressure: register slots per shape at safe strict capacity (e.g. 2 shape-rust-heavy + more light), NOT 10 equivalent heavy runners when only 2 heavy jobs are safe. A fabric-control-plane allocator (a .dag control server minting leases/JIT runners before dispatch) is the LATER architecture — only after srv1/srv2 are safely mutable and readable.
    • openProviderOffer rows + the dormant-Ubicloud design-break probe — srv1/srv2 fixed-host slots and Ubicloud ephemeral VMs inhabit the same offer type; add the Ubicloud row Dormant (16 vCPU/48GiB arm64, oversubscription: None) without running it. Acceptance = adding the offer changes no scheduler/control-plane invariant: witnesses prove (a) allocation accepts both SrvHostSlot and UbicloudVmOffer, (b) host-mutation code REFUSES Ubicloud offers (no cgroup target to mutate), (c) deploy-to-srv1 refuses LocalShell unless the allocation target proves host=srv1, (d) emitted labels encode shape, not provider host details. If adding Ubicloud forces a special case anywhere, the abstraction is wrong — this probe answers "does our design break?" before it can cost anything.
      • openBurstLease (Policy 1) — oversubscription earned by receipts — co-resident allocations on one host only after pressure/OOM/swap receipts prove the measured peaks allow it; StrictLease stays the default and the fallback. This is where stranded cores come back (sessions, compression, IO, smaller jobs) — on 128c/125GiB, strict memory allocation strands CPU and that is correct: the first goal is non-death, not full utilization. Gated on the sound-host-admission receipts and the live read seam.

Ordering (operator-signed): ① CD target-host proof → ② stateless-frontend MVP receipt (milestone A, on the existing deploy path) → ③ live read seam + privilege model → ④ one converge hunk closed-loop end-to-end (the narrow srv2 acceptance case) → ⑤ service allocation generalized from the frontend MVP → ⑥ StrictLease + shape labels; register srv1/srv2 slots by shape → ⑦ dormant Ubicloud row proves no design break → ⑧ CI jobs move to shape labels → ⑨ receipts (effective limits · peaks · OOM/swap pressure) → ⑩ BurstLease / dynamic routing / richer placement. ①–④ make infra changeable (everything else is paper until then); ⑤ proves the fabric is not just CI; ⑥ fixes backpressure with no scheduler; ⑦ validates the abstraction before we depend on it; ⑧–⑨ make CI consume the model; ⑩ recovers stranded cores.

Fleet hardening — make our metal safe for the load it carries

  • openthe 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).
    • openSessionSliceEnforcement + 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.
    • openOOM 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
  • openresource-aware scheduler (implementation) — implements the signed bounded-input / cost-envelope scheduling 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
  • openresource 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).carriergrounding
  • openone 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.

3. The floor — audit what we have (does it actually do what it claims?)

Both pillars ride the CI floor: tree-wide marker-driven witness discovery · compile-clean gate · generated-artifact drift gates (this document is one) · regen --verify (#5873) · doc-graph reachability · emit-determinism (#5941) · the interim self-host comparison (#6009). Those stand. The floor's expansion lanes (testgen, wiring-liveness, complexity gates, lens meta-walls) are shelved — a new wall must displace a measured cost on a pillar path to un-shelve (the enforcement-intent gate below is the first such un-shelve, 2026-07-02: displaced cost = the operator's repeated manual what-is-enforced-by-what-lens-over-what-corpus join, plus CI-killing quadratics and repeated dual-representation/anemia rediscovery).

Audit directive (operator, 2026-07-01): thoroughly audit what we have and what it actually does. For each load-bearing mechanism, prove by execution that it does what it claims, with a discriminating perturb that goes RED when the behavior is wrong — a typecheck or a grep is not a consumer (DESIGN §5), and a wired gate can still be vacuous. A mechanism claim without a red-control is unverified, whatever its docs say. The reset's own mapping found the pattern live: the committed converge shell is spec-without-execution (§2), the fixpoint gate self-declares interim (2-of-92 files), cargo-green is an ignored test. Highest-stakes mechanisms first:

Audit — green by execution, red by perturbation

  • openaffected-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.i:high v:med gunbc
  • donemechanism 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.@dispatched 2026-07-01 · adhoc-c67edbed-916i:med v:large gunbcplan
  • opencache 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.
  • openartifact-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.i:med v:small gunbc
  • openone 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.
  • openenforcement 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 CoverageReceipts) · 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

Cost / risk / benefit — the floor's unmodeled optimization

  • openmodel cost/risk/benefit — "what do we actually run" is one optimization, not a pile of policies (operator working session 2026-07-12) — affected-set, wet/dry (mocks), receipt/long, ReadsLiveTree never-skip, and the test-kind names (test/receipt/demo/integration, WitnessKind, TestClassification) are all unmodeled proxies for argmax(benefit − cost) under a budget — hand-tuned stand-ins (mostly astrology) that exist because cost/risk/benefit were never first-class. Root anemia: test fn bakes in cost ≈ 0, run always, which is false (s1_closure ≈ 10min wet). Invariant that keeps it fail-closed: you may trade fidelity for cost (mocks, skips, deferrals), but the risk you trade away must stay observable on a cadence — deferred-and-detected, never silent (§5; a silent widen is the absorbing fallback). This inverts the tree's current wet-is-sacred default: wet is just the highest-cost fidelity point, usually not worth it. Bootstrappable now: a claim's expected internal work is inspectable (inputs/expected-output node shape) and its effects enumerable (which service ops, how many times via fold/loop bounds), each effect carrying a latency expectation; the floor already MEASURES wall_nanos/cgroup-peak per claim, so cost = measured receipt now → graph-derived later (§4). Landed as approximation in #6506 (Stages 0–2): hermetic-by-default floor, a flat hand-set 5s per-witness budget (fail-closed EvalBudgetExceeded), and a test/claim/long/ cadence — right shape, interim stand-ins; forward work is Stages 3–5. Missing pieces (highlighted, not papered over): no per-effect cost model; cost only bounded by the flat 5s budget, not derived from the graph (fail-closed = expensive on unknown fold bounds); the budget is flat/hand-set, not a per-run wall-clock allocated by value/cost; benefit unmodeled — only footholds are the §5 lower bound (no discriminating red ⟹ ~0 gate-value ⟹ drop, this is what a pure demo is) and observed red-frequency; the proxies aren't yet reconciled to the axes. Sequence: cost first (compute/resources, from what's measurable now) with budget-aware admission and counted typed deferrals (never silent skip) → benefit second (§5 lower bound + red-frequency, declared interim for the rest) → then affected-set/wet-dry/cadence/test-kinds collapse into derived readings and the qualitative vocabulary is deleted, not extended.cost/risk/benefit model

Open floor holes

  • opennightly full-corpus selector-backstop — per-PR selection is only sound because nightly runs everything; ⚠ CI-gen load-bearing
  • opentree-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) openforce-check plan
  • openkill sccache false-greens — exit-0-no-binary; build-verify asserts the artifact exists + is fresh (partly landed in ci.yml)

4. Shelved (parked 2026-07-01 — not deleted)

Every lane below was live roadmap before the reset. Shelved = plan docs and carriers stay in place, nothing dispatches from here, and the git-history ROADMAP.md holds the full pre-reset detail (structure, milestones, sign-off states). Un-shelve by PR into §1–§3, priced in displaced cost. (2026-07-06: the complexity budget whole-codebase, fail-closed meta band, and fold-ergonomics lanes are un-shelved into §0's priority order ② and ⑤ — this reshuffle is that PR; their nodes stay catalogued here until relocated into their §2/§3 lanes.)

  • openfold-ergonomics lane — inert-abstraction lens · non-fold-residue audit · staging combinator · ban source comments charter residue catalogue debt sample audit eval-bind PROPOSE
  • openfail-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 fork plan Disposition reference grounding cardinality P1 where-lowering frontier inert-layer lens axiom lens self-applying construction rule
  • openrust-gate .dag→rust coverage wall (edge-b) + stage0 clone-census ratchet brief
  • opencomplexity budget whole-codebase + the algebraic-rewrite construction engine (O(n²)→O(n) catalog, Unknown dissolution) rewrite plan
  • opentestgen oracle + wiring-liveness family (compile-time wiring lens ✓ #5679 · pre-send guard ✓ #5683 stand; the generator/preflight expansion parks) method wiring
  • opencaching 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 M4 M5
  • openCI inline-shell de-fork · interpreter terminal-output de-fork (seed forks of modeled authorities; both shrink as v1 burns down) emission-ingestion
  • openidea 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 format reconciliation invert
  • openshell-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
  • openTypeScript first-class emit + TS self-host — END GOAL UNCHANGED (both realizations, per plan do-not-relitigate); resumes after the Rust fixed point gap census
  • openlanguage-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 solve rationale
  • openHTML/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)
  • opensession 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
  • opengunbhub (own the Git/CI engine, closes G6) · internal repo model · compute fabric as a sellable piece
  • openprivacy / 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.
  • openstructural 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
  • opendesign sketches without an active lane orchestration-as-intent model-grounding extract node-minimal representation func-env sigs resolved-graph minimization emit-host batch isolation accelerator roundtrip commit workflow input envelope seed-debt bundle 2 resolver collision wall regime-2 shared emission
`, contentType: 'text/html; charset=utf-8', status: 200 }]; const server = require('http').createServer((req, res) => { const method = req.method || 'GET'; const rawUrl = req.url || '/'; const path = rawUrl.split('?')[0] || '/'; diff --git a/DESIGN.md b/DESIGN.md index a7d7864c4ed..8bc3e4a60fe 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -98,7 +98,7 @@ hollow alias (minimality ≠ grounding) · state-space conflation (an `Option`/` - **namespace-only name resolution — the containment tree is the single naming authority (operator-signed 2026-07-06).** Supersedes resolver-graph-major §1c's *import-name-universe* ("own declarations ∪ direct import lists" visibility), carrying forward its mechanics unchanged (binding-edge owner, unbound/double-bound = error, patterns-via-scrutinee, no expected-type picker). One structure — **syntactic containment** — induces everything at once: qualified name = nesting position (`T{a}` → `a` *is* `T.a`; `T{a{a}}` → inner *is* `T.a.a`, so Rule-2 no-ambiguity holds by construction), reference = lexical lookup up the ancestor chain (a sibling module is visible, its members projected `node.Symbol`), `.` = projection one level down (field / module-member / variant — one op), and `.` *is* the `std.induction` sub-value relation (descent evidence). So one content-addressed tree grounds THREE consumers — resolution *walks* it, content-addressing *hashes* it, termination reads its *sub-value* edges (§2 Realization: one structure, N consumers). Frontend BUILDS the tree from nesting (pure structure, zero resolution logic); backend WALKS it (lexical up, project down) — no heuristics to tune (the tuning risk = resolving against a flat index instead of the tree). Two governing rules (operator, 2026-07-06): **no dual representation / minimal at every layer; no ambiguity at any layer.** Rides on `SymbolIndex` = "the containment tree materialized" (`type-env-single-authority`, lively-raven lane), gated on loyal-heron's scaling receipt before any resolver surgery; `import-scoped` (§1c, today) and `namespace-only-Y` (position-info uniqueness: expected type filters a variant to one, never picks) are two walk-rules over one *fill-agnostic* index (fill = whole tree; policy gates lookup, never fill). Census: 98% of names globally unique → always bare; the residue is v1-seed forks (resolve by subtree, free) + github-style variants ((Y) context-resolves); no consolidate-now forks (the census's 2 same-name flags proved to be a homonym + whole-file v1-seed duplication, not genuine cross-tree §3 forks). Terminal step: delete the `import` grammar + supporting code → `import` becomes a *parse error*, deps derived from `container.member` references (Rule-1 end-state). → [namespace-only resolution design](docs/plans/namespace-resolution-design.md) - **fleet-reconcile spine — one grain-agnostic membership diff (deploy · fleet · session).** ONE `membership_reconcile` reuses `std.change.keyed_two_way_diff` verbatim (no fork): desired set vs observed set keyed by member IDENTITY — Added/Modified → upsert, Removed → teardown-or-refuse, Unchanged → noop (absence of a hunk). A member may be a service/unit/host OR a Session (operator: 'it should all be the same'), so a new member type is a new instantiation of the same fn with its own `(key_of, key_eq, value_eq, ownership_of)` bundle — zero spine change (a Realization, §2; a forked reconcile means the genericity bought nothing). R5 teardown-owned-only is a CONSTRUCTION WALL: a Removed non-owned member yields `MemberTeardownRefused`, which has no effect arm in any apply dispatch, so the bad state is unwritable — never a post-check, never 'assume owned' (the absorbing fallback §5 forbids); ownership-unknown REFUSES too, typed/located/counted. Ownership is extracted as its own single authority (`gunbc.ownership.Ownership`) and `live_deploy`'s `DeploymentStep` re-grounds onto it (pass 2, a declared dissolution trigger — never a second `Owned|Ensured`). Pass 1 (spine + R5 + a synthetic discriminating witness the degenerate apply/retract poles cannot exercise) landed. → [membership-diff reconcile spine design](docs/plans/membership-diff-reconcile-spine-design.md) - **effect grants over namespaces — dissolve `Hermetic | Wet` into (frame × verb × subtree).** The 2-valued `Hermetic | Wet` enum conflates four axes (input closure / replayability, output reach / interference, handler binding, selection eligibility) — a §3 state-space conflation with proto-envelopes already forked (the hand-rolled `workspace_root` containment gate, `std.resources.ResourceHandle`, `AuthScope`, `LiveTreeDisposition`). End shape (§3, cited not minted): an effect target is a position in a containment tree that already exists — filesystem paths, URIs, `/proc`, service-operation paths, and the unifying case **code names themselves** (the containment tree the namespace-resolution lane makes the single naming authority); permission is a grant of (verb × subtree) attached to a `Frame`; admissibility is the namespace prefix relation — the same `⊑` the resolver walks, content-addressing hashes, and termination reads, so effects become the **fourth consumer** of the one containment structure. Dispatch checks the envelope fail-closed (`EffectOutsideGrant`, a typed/located/counted refusal, never a silent widen — §5); *replayable* / *isolated* / `LiveTreeDisposition` become **derived** projections, and `Hermetic | Wet | Record` survive only as named envelope presets, deleted at the end. Frame-containment is graded on the §5 construction/validation axis (`LifecycleByConstruction` vs `LifecycleByConvention`). No code lands from the design doc; the FLAG-A interim is the only near-term consumer. → [effect-namespace-grants design](docs/plans/effect-namespace-grants.md) -- **shell → intent: the intent layer is language-blind (operator-aligned 2026-07-17).** §3/§4 restated for the shell case: the `.dag` intent may not name a target language — a workflow is an ordinary dependency graph over modeled operations (§4: a program is `Node`+`Edge`), and rendering it to bash is a separate, target-parametrized concern, so bash appears exactly where Rust does (its grammar spec `src/v2/extdeps/languages/bash.dag` + the emit rows) and NOWHERE in the intent (operator: *the intent IS the `.dag` graph*; `src/v2/std/orchestration.dag` `Pipeline` is optional sugar for linear-orchestration graphs, never the authority). Two distinct downstream layers, not to be conflated: **emit** (§4 — `emit(intent, Bash)`, one grammar read backward, target as a *parameter*) and **realization** (§2 — pure-spec → host-effect, N transports `LocalShell`/`SshShell`, `dag/gunbc/host_effect_realize.dag`) — emit renders surface, realization effects a host, and realization consumes emit's output. **Invariant (enforceable, not aspirational):** the intent imports no language-construction vocab (`bash_build`, `bash_command_fold_serialize`, the `ShellStmt`/`ShellWord`/`ShellProgram` coproduct, `serialize_bash`) — that vocab is emit-internal; `src/v2/lens/realization_vocabulary_containment.dag` **generalized** with the intent layer in scope, green = *conforms to §3/§4* (the natural `StandingIntent` home). **Residual (2026-07-17, operator-flagged):** two live classes — (1) raw `concat(...)` shell strings (`dag/gunbc/ci_spec.dag` `gunbc_ci_deploy_invoke` — UNTOUCHED by the `bash_build` migration, which only migrated the `ShellStmt`/`program.dag` consumers) and (2) structured-but-still-bash (`src/v2/workflow/floor_diff_observe.dag` `floor_git_diff_unified_stmts`/`floor_serialize_program`) — census counts ~110 raw-`concat` shell fns + ~9 structured sites across ~50 files (bulk in `dag/gunbc/**`; `dag/std`/`src/v2/lens`/`src/v2/compiler` clean), collapsing to ~10 operation families (gunbc-run · source-root flags · git · cargo/rustup/tar · deploy-preflight · live_deploy · install · systemd read-back · githooks · curl) — so it is ~10 operations to model, not 110 problems. **Phases:** 0 sidecar delete (in flight — PR-A/PR-B merged, PR-C/PR-D queued) → 1 complete the agnostic emit (`Pipeline` bounded-poll/`While`, general `Retry` — the gap that pushed workflows to `bash_build`) → 2 model the operations with transports (`git.diff`, the `gunbc run` invocation, unit upsert, readiness-poll — bash-CLI as one handler of N) → 3 migrate the intent off shell → wall green throughout. Flagship: `git.diff` via `floor_diff_observe`, end-to-end intent→emit→realization. Couples to `dag/gunbc/host_effect.dag` `ShellCommand{script}` — the same bash-shaped hole one layer down (the fleet-reconcile spine's realization), which should become *run this operation* with bash-rendering downstream, not a deepened `ShellCommand{script}`. → [shell → intent design](docs/plans/shell-intent-emit-realization-design.md) +- **shell → intent: the intent layer is language-blind (operator-aligned 2026-07-17).** §3/§4 restated for the shell case: the `.dag` intent may not name a target language — a workflow is an ordinary dependency graph over modeled operations (§4: a program is `Node`+`Edge`), and rendering it to bash is a separate, target-parametrized concern, so bash appears exactly where Rust does (its grammar spec `src/v2/extdeps/languages/bash.dag` + the emit rows) and NOWHERE in the intent (operator: *the intent IS the `.dag` graph*; `src/v2/std/orchestration.dag` `Pipeline` is optional sugar for linear-orchestration graphs, never the authority). Two distinct downstream layers, not to be conflated: **emit** (§4 — `emit(intent, Bash)`, one grammar read backward, target as a *parameter*) and **realization** (§2 — pure-spec → host-effect, N transports `LocalShell`/`SshShell`, `dag/gunbc/host_effect_realize.dag`) — emit renders surface, realization effects a host, and realization consumes emit's output. **Invariant (enforceable, not aspirational):** the intent imports no language-construction vocab (`bash_build`, `bash_command_fold_serialize`, the `ShellStmt`/`ShellWord`/`ShellProgram` coproduct, `serialize_bash`) — that vocab is emit-internal; `src/v2/lens/realization_vocabulary_containment.dag` **generalized** with the intent layer in scope, green = *conforms to §3/§4* (the natural `StandingIntent` home). **Residual (2026-07-17, operator-flagged):** two live classes — (1) raw `concat(...)` shell strings (`dag/gunbc/ci_spec.dag` `gunbc_ci_deploy_invoke` — UNTOUCHED by the `bash_build` migration, which only migrated the `ShellStmt`/`program.dag` consumers) and (2) structured-but-still-bash (`src/v2/workflow/floor_diff_observe.dag` `floor_git_diff_unified_stmts`/`floor_serialize_program`) — census counts ~110 raw-`concat` shell fns + ~9 structured sites across ~50 files (bulk in `dag/gunbc/**`; `dag/std`/`src/v2/lens`/`src/v2/compiler` clean), collapsing to ~10 operation families (gunbc-run · source-root flags · git · cargo/rustup/tar · deploy-preflight · live_deploy · install · systemd read-back · githooks · curl) — so it is ~10 operations to model, not 110 problems. **Phases:** 0 sidecar delete — LANDED (#6831) → **1 complete the agnostic emit — LANDED (#6832):** `While`/`BoundedPoll`/general `Retry` (N-level escalation) emit; production consumer `ci_floor_peak_emit.dag` → 2 model the operations with transports (`git.diff`, the `gunbc run` invocation, unit upsert, readiness-poll — bash-CLI as one handler of N) → 3 migrate the intent off shell → wall green throughout. Flagship: `git.diff` via `floor_diff_observe`, end-to-end intent→emit→realization. Couples to `dag/gunbc/host_effect.dag` `ShellCommand{script}` — the same bash-shaped hole one layer down (the fleet-reconcile spine's realization), which should become *run this operation* with bash-rendering downstream, not a deepened `ShellCommand{script}`. → [shell → intent design](docs/plans/shell-intent-emit-realization-design.md) - **srvN build-cache provisioning on host-standup subsumption spine.** Legacy `ctrl-sccache.service` is misconfigured; `ci_release_build_script()` absorbing fallback (`CARGO_BUILD_JOBS=1` then `-u RUSTC_WRAPPER`) masks the deficit (§5). Design anchor: provision sccache as a host-effect ensure on the assimilation spine (P1b after `RunnerDeploySlot`), generalizing srv3's `WorkflowEnsureActuatorToolchain` to srvN; `ProvisionBuildCache { catalog_id }` routes through `host_effect_apply`; verdict fold is `ProvisionConverged | ProvisionRefused` only. STEP 2 (fallback removal) operator-sequenced after T4 live read-back. → [srvN build-cache provisioning design](docs/plans/srvn-buildcache-provisioning-design.md) - **module identity vs storage — the path⇄module binding authority + bidirectional surfaces (operator-directed 2026-07-18).** A load-bearing file-path literal is an edge living in prose — invisible to the affected set, the resolver, content-addressing, and the effect story (§4: a program is `Node`+`Edge`). The priced incident, split correctly (PR #6856 review): the 03_normalize behavioral receipt had **zero executing consumers** — excluded by a hand `witness_exclusion_substrings` roster row while the frontier falsifier enrolls only `SelfEmitted` rows and 03_normalize was `SeedRetained` — orphaned enrollment, §6 coverage-by-illusion, the roster itself the parallel-ledger form of the missing classification; the string-hidden dependency (`sn_source_rel: String = "src/v2/compiler/03_normalize.dag"` beside a 3-library-import declaration) is the **latent** defect — admitted today the row fail-closed-defaults to `ReadsLiveTree`/never-skip (safe, unscalable — it pins the whole-tree precompute), admitted to *precise* selection it would false-skip emitter-touching PRs (cache impurity: the key wrong before the cache exists). #6775's 705-error regression shipped through the first, caught by hand. Model: a module is a node (containment subtree); a file is a **storage realization** (§2 Realization — one of N; many-to-many *in the model*, staged against the live 1:1-enforced snapshot, with provenance a coproduct `ParsedFromSource | ProducedByBehavior` so zero-file produced modules are represented honestly), so the path⇄module binding is a **derived-at-parse fact** homed on `v2.compiler.source_authority` — the frontier's hand `FrontierQualifiedModuleBinding` rows AND the host-side `build_module_path_index` producer both become projections (else two authorities remain, §3). Code references modules; only host boundaries project paths. §5 order: a typed `SourceRef` at the effect boundary makes bare-string file deps unwritable (construction); an effect-reach census lens catches the falsely-declared-hermetic case (the fail-closed default already covers undeclared), inventories the migration, and backstops until the boundary lands. Phase 0 = the admission invariant: **every witness row names an executing consumer** — `SelfEmitted` receipts on the falsifier wet cadence, quarantined known-red rows on a probe cadence *expecting red* so greening is a counted un-quarantine event; "enrolled, zero executions" itself reds. Per-surface authority is the composed relation `(module × target × root) → (paths, authority, AuthoringSurface)` — for Rust the authority side is the frontier disposition (`SeedRetained` = seed `.rs` is authority, not BothWays; `SelfEmitted` = graph is authority, BothWays only over a declared `Lossless` Rust-ingest fragment), and three oracles stay separate: surface round-trip · behavioral receipt · regen byte drift. md↔dag is **delta-first** (operator 2026-07-18: decide the graph delta first; files only capture and faithfully project it — heading toward transacting without files): the **keyed delta** on the typed document value (`design_document() -> MarkdownDocument`) IS the transaction, keyed by containment-tree node identity (stable anchor, never rendered-file position — reorder = noop, ambiguity refuses), with the file three-way compare a named capture adapter that dissolves on delta-native transacting; write-back = ingest-recovered delta → rewrite the literal declaration rows → re-emit both surfaces; fidelity prerequisite priced (the ingester's `TextInline` collapse and the deliberate emphasis non-roundtrip keystone move first); `BothWays` gated on `ingest(emit(authority)) == authority` over the actual construct set (replacing the vacuous `artifact_extra_valid` arm); concurrent divergent edits refuse with a typed conflict, never last-writer-wins; yaml ingest is evidence for grammar-owned backward reads, not write-back (ci.yml stays DagOnly deliberately). Phases 0–3 take no dependency on the namespace terminal or effect-grants; flagships = the cssl transport de-stringed (receipt selected on emitter-touch, skipped on unrelated, both by execution), a DESIGN.md md-side edit landing in `design_document.dag` with the drift gate green, and the Phase-3 Rust loop (pilot `parse_engine_hooks`: edit a supported declaration in the emitted artifact → same semantic graph delta → re-emit → **edited-vs-re-emitted** behavioral equivalence, seed-equality only the no-edit control; committed seed `.rs` = hand-retained oracle, storage role decided by policy never basename). → [module identity vs storage design](docs/plans/module-identity-storage-binding-design.md) diff --git a/ROADMAP.md b/ROADMAP.md index dfb36567886..714bf1fa46c 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -103,6 +103,7 @@ Receipts + adjacent levers: [fractal Gantt](docs/plans/ci-floor-fractal-gantt.md - [x] **slice 0 — CI EAGAIN-retry** ✓ (#6467) — `ci_cargo_eagain_retry_core` → `emit(Retry, Bash)`; byte-oracle = committed `ci.yml` [plan](docs/plans/shell-emission-model.md) — ✓ signed off: operator - [x] **slice 1 — control-flow emit (census-scoped)** ✓ (#6475; tier-2 Procedure/Let band #6566) — the `If` band only (`orch_emit_step::If` + else + condition forms + pipes/cmdsubst/`$?`/AndOr/redirect/env words, byte goldens); `For`/`While` NOT in scope — the pre-runtime census (2026-07-03) found zero pre-runtime sites needing them [plan](docs/plans/shell-emission-model.md) — ✓ signed off: operator - [ ] **slice 2 — converge thin-run** *(IN FLIGHT 2026-07-14 — FLAGs 2a(i)/2b/2c operator-signed, keystone worker dispatched; [census](docs/plans/shell-to-dag-residual-census-and-arc-completion.md) §2)* — fleet_converge steady-state moves into the binary as a typed plan via `apply()` (models `EmitArtifactThenThinRun`); emitted bash shrinks to the fresh-standup/self-repair bootstrap fragment + a thin invocation line (supersedes 'emit the whole `.github/fleet-converge.sh`') [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. diff --git a/dag/gunbc/design_document.dag b/dag/gunbc/design_document.dag index 8b8086e59fa..711c07bb533 100644 --- a/dag/gunbc/design_document.dag +++ b/dag/gunbc/design_document.dag @@ -150,7 +150,7 @@ fn open_threads_blocks() -> List { li(text: "**namespace-only name resolution — the containment tree is the single naming authority (operator-signed 2026-07-06).** Supersedes resolver-graph-major §1c's *import-name-universe* (\"own declarations ∪ direct import lists\" visibility), carrying forward its mechanics unchanged (binding-edge owner, unbound/double-bound = error, patterns-via-scrutinee, no expected-type picker). One structure — **syntactic containment** — induces everything at once: qualified name = nesting position (`T\{a\}` → `a` *is* `T.a`; `T\{a\{a\}\}` → inner *is* `T.a.a`, so Rule-2 no-ambiguity holds by construction), reference = lexical lookup up the ancestor chain (a sibling module is visible, its members projected `node.Symbol`), `.` = projection one level down (field / module-member / variant — one op), and `.` *is* the `std.induction` sub-value relation (descent evidence). So one content-addressed tree grounds THREE consumers — resolution *walks* it, content-addressing *hashes* it, termination reads its *sub-value* edges (§2 Realization: one structure, N consumers). Frontend BUILDS the tree from nesting (pure structure, zero resolution logic); backend WALKS it (lexical up, project down) — no heuristics to tune (the tuning risk = resolving against a flat index instead of the tree). Two governing rules (operator, 2026-07-06): **no dual representation / minimal at every layer; no ambiguity at any layer.** Rides on `SymbolIndex` = \"the containment tree materialized\" (`type-env-single-authority`, lively-raven lane), gated on loyal-heron's scaling receipt before any resolver surgery; `import-scoped` (§1c, today) and `namespace-only-Y` (position-info uniqueness: expected type filters a variant to one, never picks) are two walk-rules over one *fill-agnostic* index (fill = whole tree; policy gates lookup, never fill). Census: 98% of names globally unique → always bare; the residue is v1-seed forks (resolve by subtree, free) + github-style variants ((Y) context-resolves); no consolidate-now forks (the census's 2 same-name flags proved to be a homonym + whole-file v1-seed duplication, not genuine cross-tree §3 forks). Terminal step: delete the `import` grammar + supporting code → `import` becomes a *parse error*, deps derived from `container.member` references (Rule-1 end-state). → [namespace-only resolution design](docs/plans/namespace-resolution-design.md)"), li(text: "**fleet-reconcile spine — one grain-agnostic membership diff (deploy · fleet · session).** ONE `membership_reconcile` reuses `std.change.keyed_two_way_diff` verbatim (no fork): desired set vs observed set keyed by member IDENTITY — Added/Modified → upsert, Removed → teardown-or-refuse, Unchanged → noop (absence of a hunk). A member may be a service/unit/host OR a Session (operator: 'it should all be the same'), so a new member type is a new instantiation of the same fn with its own `(key_of, key_eq, value_eq, ownership_of)` bundle — zero spine change (a Realization, §2; a forked reconcile means the genericity bought nothing). R5 teardown-owned-only is a CONSTRUCTION WALL: a Removed non-owned member yields `MemberTeardownRefused`, which has no effect arm in any apply dispatch, so the bad state is unwritable — never a post-check, never 'assume owned' (the absorbing fallback §5 forbids); ownership-unknown REFUSES too, typed/located/counted. Ownership is extracted as its own single authority (`gunbc.ownership.Ownership`) and `live_deploy`'s `DeploymentStep` re-grounds onto it (pass 2, a declared dissolution trigger — never a second `Owned|Ensured`). Pass 1 (spine + R5 + a synthetic discriminating witness the degenerate apply/retract poles cannot exercise) landed. → [membership-diff reconcile spine design](docs/plans/membership-diff-reconcile-spine-design.md)"), li(text: "**effect grants over namespaces — dissolve `Hermetic | Wet` into (frame × verb × subtree).** The 2-valued `Hermetic | Wet` enum conflates four axes (input closure / replayability, output reach / interference, handler binding, selection eligibility) — a §3 state-space conflation with proto-envelopes already forked (the hand-rolled `workspace_root` containment gate, `std.resources.ResourceHandle`, `AuthScope`, `LiveTreeDisposition`). End shape (§3, cited not minted): an effect target is a position in a containment tree that already exists — filesystem paths, URIs, `/proc`, service-operation paths, and the unifying case **code names themselves** (the containment tree the namespace-resolution lane makes the single naming authority); permission is a grant of (verb × subtree) attached to a `Frame`; admissibility is the namespace prefix relation — the same `⊑` the resolver walks, content-addressing hashes, and termination reads, so effects become the **fourth consumer** of the one containment structure. Dispatch checks the envelope fail-closed (`EffectOutsideGrant`, a typed/located/counted refusal, never a silent widen — §5); *replayable* / *isolated* / `LiveTreeDisposition` become **derived** projections, and `Hermetic | Wet | Record` survive only as named envelope presets, deleted at the end. Frame-containment is graded on the §5 construction/validation axis (`LifecycleByConstruction` vs `LifecycleByConvention`). No code lands from the design doc; the FLAG-A interim is the only near-term consumer. → [effect-namespace-grants design](docs/plans/effect-namespace-grants.md)"), - li(text: "**shell → intent: the intent layer is language-blind (operator-aligned 2026-07-17).** §3/§4 restated for the shell case: the `.dag` intent may not name a target language — a workflow is an ordinary dependency graph over modeled operations (§4: a program is `Node`+`Edge`), and rendering it to bash is a separate, target-parametrized concern, so bash appears exactly where Rust does (its grammar spec `src/v2/extdeps/languages/bash.dag` + the emit rows) and NOWHERE in the intent (operator: *the intent IS the `.dag` graph*; `src/v2/std/orchestration.dag` `Pipeline` is optional sugar for linear-orchestration graphs, never the authority). Two distinct downstream layers, not to be conflated: **emit** (§4 — `emit(intent, Bash)`, one grammar read backward, target as a *parameter*) and **realization** (§2 — pure-spec → host-effect, N transports `LocalShell`/`SshShell`, `dag/gunbc/host_effect_realize.dag`) — emit renders surface, realization effects a host, and realization consumes emit's output. **Invariant (enforceable, not aspirational):** the intent imports no language-construction vocab (`bash_build`, `bash_command_fold_serialize`, the `ShellStmt`/`ShellWord`/`ShellProgram` coproduct, `serialize_bash`) — that vocab is emit-internal; `src/v2/lens/realization_vocabulary_containment.dag` **generalized** with the intent layer in scope, green = *conforms to §3/§4* (the natural `StandingIntent` home). **Residual (2026-07-17, operator-flagged):** two live classes — (1) raw `concat(...)` shell strings (`dag/gunbc/ci_spec.dag` `gunbc_ci_deploy_invoke` — UNTOUCHED by the `bash_build` migration, which only migrated the `ShellStmt`/`program.dag` consumers) and (2) structured-but-still-bash (`src/v2/workflow/floor_diff_observe.dag` `floor_git_diff_unified_stmts`/`floor_serialize_program`) — census counts ~110 raw-`concat` shell fns + ~9 structured sites across ~50 files (bulk in `dag/gunbc/**`; `dag/std`/`src/v2/lens`/`src/v2/compiler` clean), collapsing to ~10 operation families (gunbc-run · source-root flags · git · cargo/rustup/tar · deploy-preflight · live_deploy · install · systemd read-back · githooks · curl) — so it is ~10 operations to model, not 110 problems. **Phases:** 0 sidecar delete (in flight — PR-A/PR-B merged, PR-C/PR-D queued) → 1 complete the agnostic emit (`Pipeline` bounded-poll/`While`, general `Retry` — the gap that pushed workflows to `bash_build`) → 2 model the operations with transports (`git.diff`, the `gunbc run` invocation, unit upsert, readiness-poll — bash-CLI as one handler of N) → 3 migrate the intent off shell → wall green throughout. Flagship: `git.diff` via `floor_diff_observe`, end-to-end intent→emit→realization. Couples to `dag/gunbc/host_effect.dag` `ShellCommand\{script\}` — the same bash-shaped hole one layer down (the fleet-reconcile spine's realization), which should become *run this operation* with bash-rendering downstream, not a deepened `ShellCommand\{script\}`. → [shell → intent design](docs/plans/shell-intent-emit-realization-design.md)"), + li(text: "**shell → intent: the intent layer is language-blind (operator-aligned 2026-07-17).** §3/§4 restated for the shell case: the `.dag` intent may not name a target language — a workflow is an ordinary dependency graph over modeled operations (§4: a program is `Node`+`Edge`), and rendering it to bash is a separate, target-parametrized concern, so bash appears exactly where Rust does (its grammar spec `src/v2/extdeps/languages/bash.dag` + the emit rows) and NOWHERE in the intent (operator: *the intent IS the `.dag` graph*; `src/v2/std/orchestration.dag` `Pipeline` is optional sugar for linear-orchestration graphs, never the authority). Two distinct downstream layers, not to be conflated: **emit** (§4 — `emit(intent, Bash)`, one grammar read backward, target as a *parameter*) and **realization** (§2 — pure-spec → host-effect, N transports `LocalShell`/`SshShell`, `dag/gunbc/host_effect_realize.dag`) — emit renders surface, realization effects a host, and realization consumes emit's output. **Invariant (enforceable, not aspirational):** the intent imports no language-construction vocab (`bash_build`, `bash_command_fold_serialize`, the `ShellStmt`/`ShellWord`/`ShellProgram` coproduct, `serialize_bash`) — that vocab is emit-internal; `src/v2/lens/realization_vocabulary_containment.dag` **generalized** with the intent layer in scope, green = *conforms to §3/§4* (the natural `StandingIntent` home). **Residual (2026-07-17, operator-flagged):** two live classes — (1) raw `concat(...)` shell strings (`dag/gunbc/ci_spec.dag` `gunbc_ci_deploy_invoke` — UNTOUCHED by the `bash_build` migration, which only migrated the `ShellStmt`/`program.dag` consumers) and (2) structured-but-still-bash (`src/v2/workflow/floor_diff_observe.dag` `floor_git_diff_unified_stmts`/`floor_serialize_program`) — census counts ~110 raw-`concat` shell fns + ~9 structured sites across ~50 files (bulk in `dag/gunbc/**`; `dag/std`/`src/v2/lens`/`src/v2/compiler` clean), collapsing to ~10 operation families (gunbc-run · source-root flags · git · cargo/rustup/tar · deploy-preflight · live_deploy · install · systemd read-back · githooks · curl) — so it is ~10 operations to model, not 110 problems. **Phases:** 0 sidecar delete — LANDED (#6831) → **1 complete the agnostic emit — LANDED (#6832):** `While`/`BoundedPoll`/general `Retry` (N-level escalation) emit; production consumer `ci_floor_peak_emit.dag` → 2 model the operations with transports (`git.diff`, the `gunbc run` invocation, unit upsert, readiness-poll — bash-CLI as one handler of N) → 3 migrate the intent off shell → wall green throughout. Flagship: `git.diff` via `floor_diff_observe`, end-to-end intent→emit→realization. Couples to `dag/gunbc/host_effect.dag` `ShellCommand\{script\}` — the same bash-shaped hole one layer down (the fleet-reconcile spine's realization), which should become *run this operation* with bash-rendering downstream, not a deepened `ShellCommand\{script\}`. → [shell → intent design](docs/plans/shell-intent-emit-realization-design.md)"), li(text: "**srvN build-cache provisioning on host-standup subsumption spine.** Legacy `ctrl-sccache.service` is misconfigured; `ci_release_build_script()` absorbing fallback (`CARGO_BUILD_JOBS=1` then `-u RUSTC_WRAPPER`) masks the deficit (§5). Design anchor: provision sccache as a host-effect ensure on the assimilation spine (P1b after `RunnerDeploySlot`), generalizing srv3's `WorkflowEnsureActuatorToolchain` to srvN; `ProvisionBuildCache { catalog_id }` routes through `host_effect_apply`; verdict fold is `ProvisionConverged | ProvisionRefused` only. STEP 2 (fallback removal) operator-sequenced after T4 live read-back. → [srvN build-cache provisioning design](docs/plans/srvn-buildcache-provisioning-design.md)"), li(text: "**module identity vs storage — the path⇄module binding authority + bidirectional surfaces (operator-directed 2026-07-18).** A load-bearing file-path literal is an edge living in prose — invisible to the affected set, the resolver, content-addressing, and the effect story (§4: a program is `Node`+`Edge`). The priced incident, split correctly (PR #6856 review): the 03_normalize behavioral receipt had **zero executing consumers** — excluded by a hand `witness_exclusion_substrings` roster row while the frontier falsifier enrolls only `SelfEmitted` rows and 03_normalize was `SeedRetained` — orphaned enrollment, §6 coverage-by-illusion, the roster itself the parallel-ledger form of the missing classification; the string-hidden dependency (`sn_source_rel: String = \"src/v2/compiler/03_normalize.dag\"` beside a 3-library-import declaration) is the **latent** defect — admitted today the row fail-closed-defaults to `ReadsLiveTree`/never-skip (safe, unscalable — it pins the whole-tree precompute), admitted to *precise* selection it would false-skip emitter-touching PRs (cache impurity: the key wrong before the cache exists). #6775's 705-error regression shipped through the first, caught by hand. Model: a module is a node (containment subtree); a file is a **storage realization** (§2 Realization — one of N; many-to-many *in the model*, staged against the live 1:1-enforced snapshot, with provenance a coproduct `ParsedFromSource | ProducedByBehavior` so zero-file produced modules are represented honestly), so the path⇄module binding is a **derived-at-parse fact** homed on `v2.compiler.source_authority` — the frontier's hand `FrontierQualifiedModuleBinding` rows AND the host-side `build_module_path_index` producer both become projections (else two authorities remain, §3). Code references modules; only host boundaries project paths. §5 order: a typed `SourceRef` at the effect boundary makes bare-string file deps unwritable (construction); an effect-reach census lens catches the falsely-declared-hermetic case (the fail-closed default already covers undeclared), inventories the migration, and backstops until the boundary lands. Phase 0 = the admission invariant: **every witness row names an executing consumer** — `SelfEmitted` receipts on the falsifier wet cadence, quarantined known-red rows on a probe cadence *expecting red* so greening is a counted un-quarantine event; \"enrolled, zero executions\" itself reds. Per-surface authority is the composed relation `(module × target × root) → (paths, authority, AuthoringSurface)` — for Rust the authority side is the frontier disposition (`SeedRetained` = seed `.rs` is authority, not BothWays; `SelfEmitted` = graph is authority, BothWays only over a declared `Lossless` Rust-ingest fragment), and three oracles stay separate: surface round-trip · behavioral receipt · regen byte drift. md↔dag is **delta-first** (operator 2026-07-18: decide the graph delta first; files only capture and faithfully project it — heading toward transacting without files): the **keyed delta** on the typed document value (`design_document() -> MarkdownDocument`) IS the transaction, keyed by containment-tree node identity (stable anchor, never rendered-file position — reorder = noop, ambiguity refuses), with the file three-way compare a named capture adapter that dissolves on delta-native transacting; write-back = ingest-recovered delta → rewrite the literal declaration rows → re-emit both surfaces; fidelity prerequisite priced (the ingester's `TextInline` collapse and the deliberate emphasis non-roundtrip keystone move first); `BothWays` gated on `ingest(emit(authority)) == authority` over the actual construct set (replacing the vacuous `artifact_extra_valid` arm); concurrent divergent edits refuse with a typed conflict, never last-writer-wins; yaml ingest is evidence for grammar-owned backward reads, not write-back (ci.yml stays DagOnly deliberately). Phases 0–3 take no dependency on the namespace terminal or effect-grants; flagships = the cssl transport de-stringed (receipt selected on emitter-touch, skipped on unrelated, both by execution), a DESIGN.md md-side edit landing in `design_document.dag` with the drift gate green, and the Phase-3 Rust loop (pilot `parse_engine_hooks`: edit a supported declaration in the emitted artifact → same semantic graph delta → re-emit → **edited-vs-re-emitted** behavioral equivalence, seed-equality only the no-edit control; committed seed `.rs` = hand-retained oracle, storage role decided by policy never basename). → [module identity vs storage design](docs/plans/module-identity-storage-binding-design.md)"), ]), diff --git a/dag/gunbc/plans/shell_emission_model.dag b/dag/gunbc/plans/shell_emission_model.dag index 8327ea05588..e959e07fc58 100644 --- a/dag/gunbc/plans/shell_emission_model.dag +++ b/dag/gunbc/plans/shell_emission_model.dag @@ -14,7 +14,7 @@ fn shell_emission_model_body() -> List { li(text: "**Intent coproduct exists** — `src/v2/std/orchestration.dag`: `Run` / `Step\{Do,If,For,While,Retry\}` / `Pipeline` / `Predicate`."), li(text: "**Bidirectional bash language exists** — `src/v2/extdeps/languages/bash.dag` (~2201 lines, POSIX-cited)."), li(text: "**Intent→bash lowering exists but is bespoke** — `src/v2/compiler/05_emit_orchestration.dag` is a per-construct dispatcher, **not** the same `target_model_edge_translation_rules` table that emits Rust/TS (`06_translate.dag` has zero orchestration refs)."), - li(text: "**Control-flow emission — the `If` band has since LANDED (verified 2026-07-16).** The 'all return `outcome_rejected`' text was written 2026-07-03 and is superseded: `05_emit_orchestration.dag:497` lowers `If` via `orch_emit_if_step` **with `else_`**, and every `Predicate` arm lowers (`ExitZero`, `StrEq`, `StrEmpty`, `StrNonempty`, `LogMatches`, `Not`, `And`, `Or`). `Retry` lowers with `on_exhausted` threaded. `For`/`While` still return `outcome_rejected` **by design** — the 2026-07-03 census found every live `For`/`While`/trap/background site is RUNTIME-PRESENT (dissolves to typed folds + argv/Pipeline interpreted by the binary), so only the `If` band is pre-runtime-justified; this is a decision, not a gap. `Run.command:String` remains the **same anemic leaf** as `host_effect.ShellCommand.script` — dissolution target `Do\{effect\}` with typed effect leaves ([host-effect-orchestration](host-effect-orchestration.md) effect-plan band)."), + li(text: "**Control-flow emission — the `If` band has since LANDED (verified 2026-07-16).** The 'all return `outcome_rejected`' text was written 2026-07-03 and is superseded: `05_emit_orchestration.dag:497` lowers `If` via `orch_emit_if_step` **with `else_`**, and every `Predicate` arm lowers (`ExitZero`, `StrEq`, `StrEmpty`, `StrNonempty`, `LogMatches`, `Not`, `And`, `Or`). `Retry` lowers with `on_exhausted` threaded. `For` still returns `outcome_rejected` (census-scoped — RUNTIME-PRESENT `For`/trap/background sites dissolve to typed folds + argv/Pipeline interpreted by the binary). **`While`/`BoundedPoll` lowering has since LANDED (#6832):** the 2026-07-03 'zero pre-runtime `While` sites' finding was superseded when a pre-runtime readiness-poll (`ci_floor_peak_emit`) required it, so `While` is emitter-supported and no longer refuses; this is a decision that was revisited, not a gap. `Run.command:String` remains the **same anemic leaf** as `host_effect.ShellCommand.script` — dissolution target `Do\{effect\}` with typed effect leaves ([host-effect-orchestration](host-effect-orchestration.md) effect-plan band)."), ]), h2(text: "2. The model (locked)"), p(text: "**ADOPT:** `intent(std)` → `bash(extdeps)` via `emit(intent, Bash)`, extending the existing dispatcher."), @@ -26,7 +26,7 @@ fn shell_emission_model_body() -> List { p(text: "Bash is a **normal medium, not a privileged exception** — grammar rows, emit, and (eventually) ingest with explicit `DecodeFidelity`; its lossless fragment is intentionally small, and ambiguous bash **fails closed** with a typed refusal rather than becoming authority. Bash is emitted only where its low-dependency property is essential: **(a) foreign executors** that require shell payloads (GHA `run:` blocks, cron entry lines, autoinstall late-commands, git hook files) and **(b) bootstrap windows** before the gunbc runtime or a typed transport exists on the host. Where the runtime IS present, effects are typed argv invocations (extdeps service ops), typed transports (REST/Redfish), or binary-interpreted effect-plan values (`EmitArtifactThenThinRun`) — never generated scripts."), p(text: "**Process invocation is not bash-the-language:** a typed argv (program + args → exit/stdout) needs no bash semantics; most `shell.Exec.Run` sites are invocations wearing bash syntax. **Slice scope derives from the pre-runtime census, not from the existing bash inventory.** New non-thin bash surface outside the two sanctioned windows requires a live leak fact, roster entry, dissolve trigger, and sign-off. Thin-run guardrail: the binary must interpret a **typed plan** and emit typed receipts — replacing an opaque bash script with an opaque imperative driver is no progress; the typed plan stays the authority. *(Supersedes the ci-humming T5 framing of the emitted converge shell as the steady-state handler: srv1/srv2 converge arms reclassify to binary-interpreted; only the fresh-standup/self-repair bootstrap arm stays emitted bash.)*"), p(text: "→ **Typed authority (sign-ready draft):** [provisioning-window-executor-capability-design.md](provisioning-window-executor-capability-design.md) — formalizes the two sanctioned windows as `ExecutorCapability` + `ProvisioningWindow` with an `authorize_shell_emission` predicate, census row table, and lens sequencing (M0–M3)."), - p(text: "**Pre-runtime census receipt (2026-07-03):** PRE-RUNTIME = GHA `run:` bodies (slice-0 retry, the 8 `ci_workflow` RunSteps, bmc smoke), cron entry lines, the fleet-converge fresh-standup arm, a pre-push thin shim, future autoinstall late-commands (today: zero shell — pure cloud-config YAML). RUNTIME-PRESENT = the entire srv3 install tail (executes on srv1 via `shell.Exec.Run` from inside `gunbc run`), live_deploy (srv1 LocalShell), the `dag/tools` witness transports (invoked from `claim_executor`), fleet-converge srv1/srv2 arms. Derived pre-runtime construct scope: Run sequencing · If-with-else (exit-status / negated-pipeline / `[ ]` tests) · pipes · cmdsubst assignment · `$?`/exit propagation · AndOr · redirects incl. `>>` · env-scoped invocation · `set` framing · Retry (landed) · one `TargetArchitecture` dispatch replacing `case uname`. NOT justified at any pre-runtime site: `For`, `While`, trap, background `&`, functions, arrays, arithmetic, process substitution."), + p(text: "**Pre-runtime census receipt (2026-07-03):** PRE-RUNTIME = GHA `run:` bodies (slice-0 retry, the 8 `ci_workflow` RunSteps, bmc smoke), cron entry lines, the fleet-converge fresh-standup arm, a pre-push thin shim, future autoinstall late-commands (today: zero shell — pure cloud-config YAML). RUNTIME-PRESENT = the entire srv3 install tail (executes on srv1 via `shell.Exec.Run` from inside `gunbc run`), live_deploy (srv1 LocalShell), the `dag/tools` witness transports (invoked from `claim_executor`), fleet-converge srv1/srv2 arms. Derived pre-runtime construct scope: Run sequencing · If-with-else (exit-status / negated-pipeline / `[ ]` tests) · pipes · cmdsubst assignment · `$?`/exit propagation · AndOr · redirects incl. `>>` · env-scoped invocation · `set` framing · Retry (landed) · one `TargetArchitecture` dispatch replacing `case uname`. NOT justified at any pre-runtime site (2026-07-03 census — superseded for `While` by #6832, which landed `While`/`BoundedPoll` emit for the `ci_floor_peak_emit` readiness-poll): `For`, trap, background `&`, functions, arrays, arithmetic, process substitution."), CodeBlock { code: "std/orchestration (intent) → 05_emit_orchestration (dispatcher)\n → v2.extdeps.languages.bash (rows)\n → shell text\n" }, h2(text: "3. Effects are first-class (load-bearing)"), p(text: "**host_effect Phase B:** the `ShellCommand\{script:String\}` payload dissolves onto **modeled orchestration intent** (a `Pipeline`), **NOT** onto the doomed `program.dag`+`serialize_bash` sidecar. The existing [host-effect-orchestration.md](host-effect-orchestration.md) Phase-B text pointing at `program.dag` **predates** `emit(intent,Bash)` and is **superseded** by this plan."), @@ -39,13 +39,13 @@ fn shell_emission_model_body() -> List { h2(text: "5. Slice sequence (each gated by a frozen committed byte oracle)"), ol(items: [ li(text: "**Slice 0 — CI EAGAIN-retry cutover — LANDED (#6467, verified 2026-07-16).** `dag/gunbc/ci_spec.dag` `ci_cargo_eagain_retry_intent` (:222) is a real `Retry \{ body: Pipeline\{steps:[Do\{run\}], on_failure: FailFast\}, escalations, on_exhausted \}` and `ci_cargo_eagain_retry_core` (:235) routes it through `orch_emit_step(medium: bash_orchestration_emit_medium())`, matching Accepted/Rejected. Refusal carries `ci_retry_emit_refused_poison` — a deliberately-invalid marker so a rejected emission reds BOTH the committed `ci.yml` drift gate and the yaml parse gate rather than letting a hand-spelled fallback mask it (§5 refuse-never-widen). Env lowering is structured since #5868+#6137 (`EnvUnset` + multi-binding `EnvPrefixed`; the `orch_emit_run_env_welded` weld is dissolved). **Precondition RESOLVED:** `Retry.on_exhausted` is no longer emitter-ignored — `05_emit_orchestration.dag:503` threads it to `orch_emit_retry`, bound at :627 via `orch_emit_pipeline(p: on_exhausted)`. The residual `concat` at :250 is a two-part `\"set -o pipefail\\n\"` prefix, not a nested-concat blob."), - li(text: "**Slice 1 — control-flow emission (census-scoped) — LANDED (#6475; tier-2 Procedure/Let band #6566; operator-signed in `roadmap_authority.dag` `6-shell-slice1`).** The `If` band only — `orch_emit_step::If` arm with else (`05_emit_orchestration.dag:497` → `orch_emit_if_step`), the condition forms, plus pipes / cmdsubst assignment / `$?` propagation / AndOr / redirects incl. `>>` / env framing word support, each with byte goldens. Every `Predicate` arm lowers (`ExitZero`, `StrEq`, `StrEmpty`, `StrNonempty`, `LogMatches`, `Not`, `And`, `Or`). `For`/`While` emission is **NOT in scope**: the pre-runtime census found zero pre-runtime sites needing them (the mirror-retry `for` loop maps to the typed Retry/escalation model interpreted by the binary) — they refuse **by design**, which is a decision, not a gap. While `While` stays emitter-unsupported the model must say so — no inert `While.bound` carried as if meaningful (the inert field is dissolved by #6718)."), + li(text: "**Slice 1 — control-flow emission (census-scoped) — LANDED (#6475; tier-2 Procedure/Let band #6566; operator-signed in `roadmap_authority.dag` `6-shell-slice1`).** The `If` band only — `orch_emit_step::If` arm with else (`05_emit_orchestration.dag:497` → `orch_emit_if_step`), the condition forms, plus pipes / cmdsubst assignment / `$?` propagation / AndOr / redirects incl. `>>` / env framing word support, each with byte goldens. Every `Predicate` arm lowers (`ExitZero`, `StrEq`, `StrEmpty`, `StrNonempty`, `LogMatches`, `Not`, `And`, `Or`). `For` emission is **NOT in scope** (census-scoped): the mirror-retry `for` loop maps to the typed Retry/escalation model interpreted by the binary — it refuses **by design**, a decision, not a gap. **`While` emission has since LANDED (#6832):** the 2026-07-03 'zero pre-runtime `While` sites' finding was superseded by the `ci_floor_peak_emit` readiness-poll, so `While`/`BoundedPoll` now lower via `05_emit_orchestration` with byte goldens (`orchestration_while_emit_test`) and `While` is no longer emitter-unsupported (the earlier inert `While.bound` field was dissolved by #6718; #6832 gave `While` a real bound-carrying emit)."), li(text: "**Slice 2 — converge thin-run — WORK OBSERVABLY COMPLETE; operator sign-off PENDING (receipts read 2026-07-16).** Tree receipts: `.github/fleet-converge.sh` is now **21 lines** — `gunbc converge --host srv1|srv2|srv3` (ConvergePlan interpreted in-process) plus the fresh-standup bootstrap fragment, the one arm the bash-minimization rule sanctions as pre-runtime; `fleet_converge_emit.dag` has **zero** bash fn defs and emits one artifact (`expected_fleet_converge_sh`); `EmitArtifactThenThinRun` is a live `transport:` arm on `gunbc.host_effect` (`dag/test/claim/fleet_converge_apply_witness_test.dag`), no longer prose-only. The 4 for-loops / while-read drain / verdict arithmetic / 12 functions are gone. **This doc does NOT declare the slice done.** `roadmap_authority.dag` `6-shell-slice2` is the status authority and still reads `done: false` (*IN FLIGHT 2026-07-14 — FLAGs 2a(i)/2b/2c*); flipping it requires an `operator` `signed(...)` attestation, which only the operator can give — every `done: true` row in that carrier is operator-signed. The FLAGs are not resolvable from tree receipts alone. **Operator: if the FLAGs are discharged, sign `6-shell-slice2` and this row becomes LANDED.** The `~275 lines / 12+ fn defs` row in [the residual census](shell-to-dag-residual-census-and-arc-completion.md) is likewise stale against the current emitter."), li(text: "**Slice 3 — live_deploy:** RUNTIME-PRESENT (runs on srv1 over LocalShell with gunbc as the invoker) → thin-run/typed-effect candidate, **not** a golden to freeze-and-emit: heredoc file bodies become typed `Filesystem.Write` effects with foreign-media payloads as data; apt/systemctl/tailscale become typed argv invocations. Its self-referential drift gate (compares the emit fn to itself) stays named as the #6023-class trap until the reshape."), li(text: "**Slice 4 — tail consumers (pre-runtime residue):** `bmc_token_federation` (two `Do\{Run\}` rows — slice-0 machinery suffices) → `ci_workflow` inline `RunStep`s (case/`uname` → model as `TargetArchitecture`; cross-link ROADMAP §1 `1-inline-shell-defork`) → githooks as a **thin shim** (ensure-built + exec `claim_batch --pre-push` with stdin passed through; the case-rosters/arrays/while-read stdin parse move into the binary)."), ]), h2(text: "6. Sidecar dissolution (parallel)"), - p(text: "**LANDED (#6831, Phase 0):** `dag/extdeps/languages/bash/program.dag` (`ShellProgram`/`serialize_bash`) deleted; the vacuous bash-program importer-count ratchet is pruned with it (resolve fails before the ratchet could fire). Remaining arc work is intent-layer shell→`emit(intent, Bash)` migration (Categories A–C in [shell-intent-emit-realization-design.md](shell-intent-emit-realization-design.md)), not sidecar restoration."), + p(text: "**LANDED (#6831, Phase 0):** `dag/extdeps/languages/bash/program.dag` (`ShellProgram`/`serialize_bash`) deleted; the vacuous bash-program importer-count ratchet is pruned with it (resolve fails before the ratchet could fire). Remaining arc work is intent-layer shell→`emit(intent, Bash)` migration (Categories A–C in [shell-intent-emit-realization-design.md](shell-intent-emit-realization-design.md)), not sidecar restoration. **Phase 1 LANDED (#6832):** `While`/`BoundedPoll`/general `Retry` emit — see `roadmap_authority.dag` `6-shell-intent-phase1`."), p(text: "Tracked in [emission-ingestion-inverse.md](emission-ingestion-inverse.md) / `emission_ingestion_inverse.dag` — **cross-link only, do not duplicate** the roster here."), h2(text: "7. Named residue / dissolution triggers"), ul(items: [ diff --git a/dag/gunbc/roadmap_authority.dag b/dag/gunbc/roadmap_authority.dag index 189f880908b..f0c00a75216 100644 --- a/dag/gunbc/roadmap_authority.dag +++ b/dag/gunbc/roadmap_authority.dag @@ -220,6 +220,7 @@ fn section_2() -> RoadmapSection { owned(rn: authored_wi(id: "2-emit-partition", done: false, content: "**emit partition cleanup — shell/json/yaml as grammar rows, zero language knowledge in the wrong layer** *(operator directive, 2026-07-01)* — one grammar per language, read in both directions (DESIGN §4); emission is rows in `extdeps/languages/`, never stage code. Four leftovers: (a) `src/v2/compiler/05_emit_orchestration.dag` still carries orchestration→bash lowering IN the compiler stage (the retry 2-level expansion, seq-join) — the #6106 registry dispatch is the exit mechanism; the former env-weld half is DISCHARGED (#5868 grew the bash AST `EnvUnset` + multi-binding `EnvPrefixed`; #6137 dissolved `orch_emit_run_env_welded`); the stage keeps ONE agnostic fold. (b) the bash grammar itself is FORKED across trees — `dag/extdeps/languages/bash/` vs `src/v2/extdeps/languages/bash.dag`+`bash_command_fold.dag` — the same §3 class as the `extdeps.shell` fork (hotfixed #6112), one authority must win. (c) JSON has no grammar authority: N hand-rolled emitters (`roadmap_spawner`'s `json_escape`/`json_str` is a marked scaffold dissolving to `std.primitives.to_json`; `bmc_onboard` and `tailscale_acl_emit` carry their own). (d) YAML: `ci_yaml_emit`/`ci_yaml_validate`/`gha_yaml_fold_pilot` sit in `dag/gunbc/` (workflow layer) while the fold pilot is `src/v2/extdeps/languages/gha_workflow_yaml_fold.dag` — YAML-the-language rows belong in `extdeps/languages/` with GHA-workflow as rows on top, retiring the `yaml_check` Rust scaffold once parse is grammar-owned. The construction wall that makes the splice class unwritable (a string literal is an ATOM, never a COMPOSITION — joins live in `extdeps/languages` rows, never workflow code): [no-smuggled-programs wall dissolved with program.dag FULL DELETE — shell → intent design](docs/plans/shell-intent-emit-realization-design.md).", intricacy: IntricacyHigh, volume: VolumeLarge, repo: "gunbc"), owner: "dispatched 2026-07-02 · adhoc-2040cdfe-46b"), sign(rn: authored_doc(id: "6-shell-slice0", done: true, content: "**slice 0 — CI EAGAIN-retry** ✓ (#6467) — `ci_cargo_eagain_retry_core` → `emit(Retry, Bash)`; byte-oracle = committed `ci.yml`", path: "docs/plans/shell-emission-model.md"), s: signed(by: "operator", works: true, scope_equivalent: true, as_expected: true)), sign(rn: authored_doc(id: "6-shell-slice1", done: true, content: "**slice 1 — control-flow emit (census-scoped)** ✓ (#6475; tier-2 Procedure/Let band #6566) — the `If` band only (`orch_emit_step::If` + else + condition forms + pipes/cmdsubst/`$?`/AndOr/redirect/env words, byte goldens); `For`/`While` NOT in scope — the pre-runtime census (2026-07-03) found zero pre-runtime sites needing them", path: "docs/plans/shell-emission-model.md"), s: signed(by: "operator", works: true, scope_equivalent: true, as_expected: true)), + 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** *(IN FLIGHT 2026-07-14 — FLAGs 2a(i)/2b/2c operator-signed, keystone worker dispatched; [census](docs/plans/shell-to-dag-residual-census-and-arc-completion.md) §2)* — fleet_converge steady-state moves into the binary as a typed plan via `apply()` (models `EmitArtifactThenThinRun`); emitted bash shrinks to the fresh-standup/self-repair bootstrap fragment + a thin invocation line (supersedes 'emit the whole `.github/fleet-converge.sh`')", 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"), @@ -254,6 +255,7 @@ fn section_2() -> RoadmapSection { RoadmapEdge { child: nid(s: "2-runner-allocation-v0"), parent: nid(s: "2-host-admission") }, RoadmapEdge { child: nid(s: "2-debash-orchestration"), parent: nid(s: "6-shell-emission") }, RoadmapEdge { child: nid(s: "2-emit-partition"), parent: nid(s: "2-debash-orchestration") }, + RoadmapEdge { child: nid(s: "6-shell-intent-phase1"), parent: nid(s: "6-shell-emission") }, RoadmapEdge { child: nid(s: "6-shell-slice0"), parent: nid(s: "6-shell-emission") }, RoadmapEdge { child: nid(s: "6-shell-slice1"), parent: nid(s: "6-shell-slice0") }, RoadmapEdge { child: nid(s: "6-shell-slice2"), parent: nid(s: "6-shell-slice1") }, diff --git a/docs/plans/shell-emission-model.md b/docs/plans/shell-emission-model.md index a99e77098fa..9a69399052e 100644 --- a/docs/plans/shell-emission-model.md +++ b/docs/plans/shell-emission-model.md @@ -11,7 +11,7 @@ Shell is emitted as **raw strings** in the residue — `host_effect.dag` still c - **Intent coproduct exists** — `src/v2/std/orchestration.dag`: `Run` / `Step{Do,If,For,While,Retry}` / `Pipeline` / `Predicate`. - **Bidirectional bash language exists** — `src/v2/extdeps/languages/bash.dag` (~2201 lines, POSIX-cited). - **Intent→bash lowering exists but is bespoke** — `src/v2/compiler/05_emit_orchestration.dag` is a per-construct dispatcher, **not** the same `target_model_edge_translation_rules` table that emits Rust/TS (`06_translate.dag` has zero orchestration refs). -- **Control-flow emission — the `If` band has since LANDED (verified 2026-07-16).** The 'all return `outcome_rejected`' text was written 2026-07-03 and is superseded: `05_emit_orchestration.dag:497` lowers `If` via `orch_emit_if_step` **with `else_`**, and every `Predicate` arm lowers (`ExitZero`, `StrEq`, `StrEmpty`, `StrNonempty`, `LogMatches`, `Not`, `And`, `Or`). `Retry` lowers with `on_exhausted` threaded. `For`/`While` still return `outcome_rejected` **by design** — the 2026-07-03 census found every live `For`/`While`/trap/background site is RUNTIME-PRESENT (dissolves to typed folds + argv/Pipeline interpreted by the binary), so only the `If` band is pre-runtime-justified; this is a decision, not a gap. `Run.command:String` remains the **same anemic leaf** as `host_effect.ShellCommand.script` — dissolution target `Do{effect}` with typed effect leaves ([host-effect-orchestration](host-effect-orchestration.md) effect-plan band). +- **Control-flow emission — the `If` band has since LANDED (verified 2026-07-16).** The 'all return `outcome_rejected`' text was written 2026-07-03 and is superseded: `05_emit_orchestration.dag:497` lowers `If` via `orch_emit_if_step` **with `else_`**, and every `Predicate` arm lowers (`ExitZero`, `StrEq`, `StrEmpty`, `StrNonempty`, `LogMatches`, `Not`, `And`, `Or`). `Retry` lowers with `on_exhausted` threaded. `For` still returns `outcome_rejected` (census-scoped — RUNTIME-PRESENT `For`/trap/background sites dissolve to typed folds + argv/Pipeline interpreted by the binary). **`While`/`BoundedPoll` lowering has since LANDED (#6832):** the 2026-07-03 'zero pre-runtime `While` sites' finding was superseded when a pre-runtime readiness-poll (`ci_floor_peak_emit`) required it, so `While` is emitter-supported and no longer refuses; this is a decision that was revisited, not a gap. `Run.command:String` remains the **same anemic leaf** as `host_effect.ShellCommand.script` — dissolution target `Do{effect}` with typed effect leaves ([host-effect-orchestration](host-effect-orchestration.md) effect-plan band). ## 2. The model (locked) @@ -33,7 +33,7 @@ Bash is a **normal medium, not a privileged exception** — grammar rows, emit, → **Typed authority (sign-ready draft):** [provisioning-window-executor-capability-design.md](provisioning-window-executor-capability-design.md) — formalizes the two sanctioned windows as `ExecutorCapability` + `ProvisioningWindow` with an `authorize_shell_emission` predicate, census row table, and lens sequencing (M0–M3). -**Pre-runtime census receipt (2026-07-03):** PRE-RUNTIME = GHA `run:` bodies (slice-0 retry, the 8 `ci_workflow` RunSteps, bmc smoke), cron entry lines, the fleet-converge fresh-standup arm, a pre-push thin shim, future autoinstall late-commands (today: zero shell — pure cloud-config YAML). RUNTIME-PRESENT = the entire srv3 install tail (executes on srv1 via `shell.Exec.Run` from inside `gunbc run`), live_deploy (srv1 LocalShell), the `dag/tools` witness transports (invoked from `claim_executor`), fleet-converge srv1/srv2 arms. Derived pre-runtime construct scope: Run sequencing · If-with-else (exit-status / negated-pipeline / `[ ]` tests) · pipes · cmdsubst assignment · `$?`/exit propagation · AndOr · redirects incl. `>>` · env-scoped invocation · `set` framing · Retry (landed) · one `TargetArchitecture` dispatch replacing `case uname`. NOT justified at any pre-runtime site: `For`, `While`, trap, background `&`, functions, arrays, arithmetic, process substitution. +**Pre-runtime census receipt (2026-07-03):** PRE-RUNTIME = GHA `run:` bodies (slice-0 retry, the 8 `ci_workflow` RunSteps, bmc smoke), cron entry lines, the fleet-converge fresh-standup arm, a pre-push thin shim, future autoinstall late-commands (today: zero shell — pure cloud-config YAML). RUNTIME-PRESENT = the entire srv3 install tail (executes on srv1 via `shell.Exec.Run` from inside `gunbc run`), live_deploy (srv1 LocalShell), the `dag/tools` witness transports (invoked from `claim_executor`), fleet-converge srv1/srv2 arms. Derived pre-runtime construct scope: Run sequencing · If-with-else (exit-status / negated-pipeline / `[ ]` tests) · pipes · cmdsubst assignment · `$?`/exit propagation · AndOr · redirects incl. `>>` · env-scoped invocation · `set` framing · Retry (landed) · one `TargetArchitecture` dispatch replacing `case uname`. NOT justified at any pre-runtime site (2026-07-03 census — superseded for `While` by #6832, which landed `While`/`BoundedPoll` emit for the `ci_floor_peak_emit` readiness-poll): `For`, trap, background `&`, functions, arrays, arithmetic, process substitution. ``` std/orchestration (intent) → 05_emit_orchestration (dispatcher) @@ -60,14 +60,14 @@ Shell-orchestration sites are **emit-only** (regime-2 class): no round-trip orac ## 5. Slice sequence (each gated by a frozen committed byte oracle) 1. **Slice 0 — CI EAGAIN-retry cutover — LANDED (#6467, verified 2026-07-16).** `dag/gunbc/ci_spec.dag` `ci_cargo_eagain_retry_intent` (:222) is a real `Retry { body: Pipeline{steps:[Do{run}], on_failure: FailFast}, escalations, on_exhausted }` and `ci_cargo_eagain_retry_core` (:235) routes it through `orch_emit_step(medium: bash_orchestration_emit_medium())`, matching Accepted/Rejected. Refusal carries `ci_retry_emit_refused_poison` — a deliberately-invalid marker so a rejected emission reds BOTH the committed `ci.yml` drift gate and the yaml parse gate rather than letting a hand-spelled fallback mask it (§5 refuse-never-widen). Env lowering is structured since #5868+#6137 (`EnvUnset` + multi-binding `EnvPrefixed`; the `orch_emit_run_env_welded` weld is dissolved). **Precondition RESOLVED:** `Retry.on_exhausted` is no longer emitter-ignored — `05_emit_orchestration.dag:503` threads it to `orch_emit_retry`, bound at :627 via `orch_emit_pipeline(p: on_exhausted)`. The residual `concat` at :250 is a two-part `"set -o pipefail\n"` prefix, not a nested-concat blob. -2. **Slice 1 — control-flow emission (census-scoped) — LANDED (#6475; tier-2 Procedure/Let band #6566; operator-signed in `roadmap_authority.dag` `6-shell-slice1`).** The `If` band only — `orch_emit_step::If` arm with else (`05_emit_orchestration.dag:497` → `orch_emit_if_step`), the condition forms, plus pipes / cmdsubst assignment / `$?` propagation / AndOr / redirects incl. `>>` / env framing word support, each with byte goldens. Every `Predicate` arm lowers (`ExitZero`, `StrEq`, `StrEmpty`, `StrNonempty`, `LogMatches`, `Not`, `And`, `Or`). `For`/`While` emission is **NOT in scope**: the pre-runtime census found zero pre-runtime sites needing them (the mirror-retry `for` loop maps to the typed Retry/escalation model interpreted by the binary) — they refuse **by design**, which is a decision, not a gap. While `While` stays emitter-unsupported the model must say so — no inert `While.bound` carried as if meaningful (the inert field is dissolved by #6718). +2. **Slice 1 — control-flow emission (census-scoped) — LANDED (#6475; tier-2 Procedure/Let band #6566; operator-signed in `roadmap_authority.dag` `6-shell-slice1`).** The `If` band only — `orch_emit_step::If` arm with else (`05_emit_orchestration.dag:497` → `orch_emit_if_step`), the condition forms, plus pipes / cmdsubst assignment / `$?` propagation / AndOr / redirects incl. `>>` / env framing word support, each with byte goldens. Every `Predicate` arm lowers (`ExitZero`, `StrEq`, `StrEmpty`, `StrNonempty`, `LogMatches`, `Not`, `And`, `Or`). `For` emission is **NOT in scope** (census-scoped): the mirror-retry `for` loop maps to the typed Retry/escalation model interpreted by the binary — it refuses **by design**, a decision, not a gap. **`While` emission has since LANDED (#6832):** the 2026-07-03 'zero pre-runtime `While` sites' finding was superseded by the `ci_floor_peak_emit` readiness-poll, so `While`/`BoundedPoll` now lower via `05_emit_orchestration` with byte goldens (`orchestration_while_emit_test`) and `While` is no longer emitter-unsupported (the earlier inert `While.bound` field was dissolved by #6718; #6832 gave `While` a real bound-carrying emit). 3. **Slice 2 — converge thin-run — WORK OBSERVABLY COMPLETE; operator sign-off PENDING (receipts read 2026-07-16).** Tree receipts: `.github/fleet-converge.sh` is now **21 lines** — `gunbc converge --host srv1|srv2|srv3` (ConvergePlan interpreted in-process) plus the fresh-standup bootstrap fragment, the one arm the bash-minimization rule sanctions as pre-runtime; `fleet_converge_emit.dag` has **zero** bash fn defs and emits one artifact (`expected_fleet_converge_sh`); `EmitArtifactThenThinRun` is a live `transport:` arm on `gunbc.host_effect` (`dag/test/claim/fleet_converge_apply_witness_test.dag`), no longer prose-only. The 4 for-loops / while-read drain / verdict arithmetic / 12 functions are gone. **This doc does NOT declare the slice done.** `roadmap_authority.dag` `6-shell-slice2` is the status authority and still reads `done: false` (*IN FLIGHT 2026-07-14 — FLAGs 2a(i)/2b/2c*); flipping it requires an `operator` `signed(...)` attestation, which only the operator can give — every `done: true` row in that carrier is operator-signed. The FLAGs are not resolvable from tree receipts alone. **Operator: if the FLAGs are discharged, sign `6-shell-slice2` and this row becomes LANDED.** The `~275 lines / 12+ fn defs` row in [the residual census](shell-to-dag-residual-census-and-arc-completion.md) is likewise stale against the current emitter. 4. **Slice 3 — live_deploy:** RUNTIME-PRESENT (runs on srv1 over LocalShell with gunbc as the invoker) → thin-run/typed-effect candidate, **not** a golden to freeze-and-emit: heredoc file bodies become typed `Filesystem.Write` effects with foreign-media payloads as data; apt/systemctl/tailscale become typed argv invocations. Its self-referential drift gate (compares the emit fn to itself) stays named as the #6023-class trap until the reshape. 5. **Slice 4 — tail consumers (pre-runtime residue):** `bmc_token_federation` (two `Do{Run}` rows — slice-0 machinery suffices) → `ci_workflow` inline `RunStep`s (case/`uname` → model as `TargetArchitecture`; cross-link ROADMAP §1 `1-inline-shell-defork`) → githooks as a **thin shim** (ensure-built + exec `claim_batch --pre-push` with stdin passed through; the case-rosters/arrays/while-read stdin parse move into the binary). ## 6. Sidecar dissolution (parallel) -**LANDED (#6831, Phase 0):** `dag/extdeps/languages/bash/program.dag` (`ShellProgram`/`serialize_bash`) deleted; the vacuous bash-program importer-count ratchet is pruned with it (resolve fails before the ratchet could fire). Remaining arc work is intent-layer shell→`emit(intent, Bash)` migration (Categories A–C in [shell-intent-emit-realization-design.md](shell-intent-emit-realization-design.md)), not sidecar restoration. +**LANDED (#6831, Phase 0):** `dag/extdeps/languages/bash/program.dag` (`ShellProgram`/`serialize_bash`) deleted; the vacuous bash-program importer-count ratchet is pruned with it (resolve fails before the ratchet could fire). Remaining arc work is intent-layer shell→`emit(intent, Bash)` migration (Categories A–C in [shell-intent-emit-realization-design.md](shell-intent-emit-realization-design.md)), not sidecar restoration. **Phase 1 LANDED (#6832):** `While`/`BoundedPoll`/general `Retry` emit — see `roadmap_authority.dag` `6-shell-intent-phase1`. Tracked in [emission-ingestion-inverse.md](emission-ingestion-inverse.md) / `emission_ingestion_inverse.dag` — **cross-link only, do not duplicate** the roster here. diff --git a/docs/plans/shell-intent-emit-realization-design.md b/docs/plans/shell-intent-emit-realization-design.md index 3042d96b4ae..709ab650172 100644 --- a/docs/plans/shell-intent-emit-realization-design.md +++ b/docs/plans/shell-intent-emit-realization-design.md @@ -78,8 +78,8 @@ Legitimate and **excluded** from the residual: `src/v2/extdeps/languages/bash.da The headline is **"no language in the intent,"** with the sidecar delete demoted to Phase 0. -0. **Sidecar delete** (in flight — PR-A/PR-B merged, PR-C migrate-last-consumers + PR-D trivial-delete queued). Removes the `serialize_bash`/`RawLine` string-smuggling vector and consolidates bash on the one grammar. Necessary, not sufficient. -1. **Complete the agnostic emit.** `src/v2/std/orchestration.dag` emit has holes (bounded-poll/`While` rejected, `Retry` hardcoded to two levels) — the gap that pushed workflows to reach for `bash_build`. Close it so the intent graph can express what workflows need. +0. **Sidecar delete** — LANDED (#6831, Phase 0). Removes the `serialize_bash`/`RawLine` string-smuggling vector and consolidates bash on the one grammar. Necessary, not sufficient. +1. **Complete the agnostic emit — LANDED (#6832, 2026-07-18).** `While`/`BoundedPoll`/`Retry` (N-level escalation chain) emit via `05_emit_orchestration` + bash grammar rows; byte goldens in `orchestration_while_emit_test` / `orchestration_bounded_poll_emit_test` / `orchestration_retry_emit_test`; production consumer `ci_floor_peak_emit.dag` (cgroup locate `While`). 2. **Model the operations with transports.** `git.diff`, the `gunbc run` invocation, unit upsert, package fetch, readiness-poll — each a §3 operation shape in `extdeps/**` with the bash-CLI as one handler. 3. **Migrate the intent off shell.** Rewrite `gunbc_ci_deploy_invoke`, `floor_diff_observe`, `build_step_emit`, `live_deploy`, CI to build modeled-operation graphs; `bash_build` and raw `concat`-shell vanish from the intent layer. 4. **Wall green with the intent layer in scope** — the generalized `realization_vocabulary_containment`, as the standing acceptance criterion throughout.