Skip to content

Latest commit

 

History

History
334 lines (308 loc) · 30.3 KB

File metadata and controls

334 lines (308 loc) · 30.3 KB

Current state

Status: Living

Last updated: 2026-07-11

This page tracks what is active right now and the immediate next concrete actions. The full phase plan and the global milestone spine are in README.md. Phase 2.5 (CLI Consolidation) is complete (milestone M2.5-4, PR #69, 2026-07-08) — its breakdown, now historical, is in phases/phase-2.5-cli-consolidation.md. Phase 2.6 — Conversational Authoring and the First-Class CLI is in progress (re-scoped 2026-07-08); its plan is in phases/phase-2.6-conversational-authoring.md. Workstream 2.6.F (platform floor + the full-screen TUI renderer) is merged to main (PR #74, 2026-07-11). 2.6.C (the reseat transcript-carry + the /cost per-model breakdown) is complete on development (2026-07-12, PR pending) — see Active now.

Where we are

Phase 1 — Engine and LLM is COMPLETE (milestone M2 reached, PR #27, 2026-06-16; all workstreams 1.A–1.AH merged through PR #38, 2026-06-21). The engine runs end-to-end: YAML parse → DAG → run loop → node execution (agent + the six non-agent handlers) → checkpoint/resume → node retry → provider failover, with per-attempt cost tracking and a gap-free sequenceNumber. The @relavium/llm seam is frozen and proven behind a provider-agnostic LLMProvider interface with all three adapters (Anthropic, OpenAI/DeepSeek, Gemini) and the FallbackChain runner. Two additive sub-spines also completed: the agent-first entry point (AgentSession multi-turn + session persistence + export-to-workflow, Lane C / 1.m5, 1.V–1.AA) and multimodal I/O (media input + engine plumbing + inline & async output generation + generative adapters, 1.m6, 1.AD–1.AH). See Phase 1 detail, the decision index, and the reference specs.

Live maintainer obligations: (1) mark the CI ci job a required check in GitHub branch protection (carried from Phase 0; optionally add TURBO_TOKEN/TURBO_TEAM secrets for the cross-runner remote cache); (2) now that 2.L has landed (PR #49) and v0.1.1 has been cut, add the NPM_TOKEN repo secret + npm 2FA so the tag-triggered Release CLI workflow can publish — still pending for the v0.1.1 tag (the actual npm publish is maintainer-gated, ADR-0051 / release-a-surface.md).

What is active now

Phase 2.6.F — platform floor + the full-screen TUI renderer (merged to main, PR #74, 2026-07-11)

The first 2.6 workstream. Behind ADR-0067 (Node >=22 published floor, >=22.13.0 dev-install floor; better-sqlite3 re-affirmed), ADR-0068 (ink 7 + a hand-built alternate-screen renderer + the ink-testing-library harness), and ADR-0069 (string-width for display width — Accepted on the PR #74 merge, the CLAUDE.md rule-2 approval it gated).

Shipped: ink 6→7 and the component-render harness; the alt-screen lifecycle with restore nets on every termination path; a hand-built transcript viewport (grapheme-aware wrapping, windowing, scroll + auto-follow, a per-entry wrap cache) and the inter-session alt-buffer hoist; the /scrollback, /edit and /copy copy-and-search hatches over a suspendFullScreen primitive; in-app mouse text selection with copy-on-select over OSC 52 on both surfaces, with edge auto-scroll, a frozen auto-follow and a transient ✓ Copied toast so the otherwise-silent copy is confirmed; --no-mouse / [preferences].{alt_screen,mouse,copy_on_select,show_banner}; a branded Home banner; and DEC-2026 synchronized output — which ink 7 turned out to already emit, so the step pins it rather than building the planned stdout Proxy.

The full-screen renderer is now the default on a TTY; --no-alt-screen and a machine / non-TTY / --json / CI path stay on the byte-identical inline renderer.

Two adversarial review rounds (one per step, one over the whole phase) drove the last third of the work. The whole-phase round found that the caps-lift ADR-0068 exists to deliver was never implemented — a name collision with the Step-4b-3 wrap cache — so a >4000-character answer was still clipped in the very viewport built to scroll it; that displayWidth under-counted 8 539 code points against ink's own width function; and that a keyboard Ctrl-C during a Home hatch stranded mouse reporting on the user's shell. All folded, each with a break-verified regression test.

Phase 2.6.C — reseat transcript-carry + the /cost per-model breakdown (complete on development, 2026-07-12)

Driven by two maintainer manual-test findings. F1: a mid-session /models reseat blanked the alt-screen viewport — the reseat builds a fresh view store, and on the full-screen renderer (the TTY default since 2.6.F, with no native scrollback behind it) that store is the scrollback, so the whole conversation vanished the moment a user switched models. The durable transcript and the new model's context were never at risk; the loss was the view. The reseat now carries the rendered conversation, gated to full-screen (a seeded inline store would re-print the conversation over the copy ink's <Static> already put in the terminal's scrollback), and the switch notice lands beneath it as an inline ⇄ model changed <old> → <new> marker, keeping ADR-0059's bound disclosure clause.

/cost now shows where the money went, behind a new ADR-0070: a durable session_costs table with the invariant SUM(rows) == agent_sessions.total_cost_microcents, true by construction. ADR-0059 had planned to derive the breakdown from the per-message model_id, which cannot work — one row holds one model, but a turn whose tool loop fails over bills two. Along the way it closed a live bug: total_cost_microcents was being SET blindly by five writers, so two chat-resume processes could permanently corrupt a session's total. It now has a single owner. session_messages' never-written token/cost columns were dropped rather than left as a second, wrong, zero-valued source.

Four adversarial review rounds ran over the work and each found something real — including that a tripwire I shipped was armed in production and swallowed by ink (so it could never fail), that a perf harness measured a pointer assignment while its ADR note claimed it verified an O(n) bound, and that the /cost DB read — the step's central change — had zero test coverage at any layer. All folded, each with a break-verified regression.

Open obligations carried out of 2.6.C:

  • chat-resume opens on an empty viewport — it has never repainted prior turns, in any mode or version (nothing projects session_messages into rendered entries). Not a 2.6.F regression; tracked in deferred-tasks.md.
  • Reported spend is a systematic under-estimate of the provider's invoice — an egress that streamed content but ended without a usage chunk, and a mid-stream failure, are recorded as 0 on both sides of the invariant. That is a usage-capture gap in the seam, filed against 2.6.Q (ADR-0070 §3).

Open obligations carried out of 2.6.F:

  • The Home landing can overflow a short terminal — a populated "Attention required" section pushes the top off, and the alt buffer has no scrollback to recover it. Predates 2.6.F (the strip is 2.5.B); 2.6.G's management browsers replace the strip wholesale, which is the right place to fix it.
  • relavium run's TUI stays inline (a deliberate 2.6.F scope cut); its retained-scrollable-history is tracked.
  • Themes (beyond colour / NO_COLOR) are deferred to 2.6.L, per the maintainer's Step-5 decision.
  • Real-TTY signal paths (double-Ctrl-C, kill -TERM/-HUP/-QUIT, a hatch under tmux) remain a manual PR-time check — the unit tests pin the orchestration around injected seams, not the kernel.

Phase 2 — CLI (milestone M3) is feature-complete (every in-phase workstream 2.A–2.S merged; published as v0.1.1). The CLI is the first real @relavium/core consumer and doubles as the engine's regression harness — validating the engine API ergonomics before the desktop and VS Code surfaces. Landed: the CLI skeleton + process contract (2.A) and the two-level config-resolution loader (2.B), both ✅ Done (PR #40, 2026-06-22) behind ADR-0047 (commander/ink/@clack) and ADR-0048 (smol-toml); and 2.D (relavium run wired to @relavium/core — the M3 keystone and first real engine consumer), ✅ Done (PR #41, 2026-06-22), which also adds the defaultProviders() seam registry; and 2.F (the --json CI machine-output contract — pure-NDJSON stdout, diagnostics → stderr), ✅ Done (PR #42, 2026-06-22) behind ADR-0049; and 2.K (the engine regression harness, now the engine's CI regression gate), ✅ Done (PR #43, 2026-06-23) — reaching global milestone M3; and 2.H (durable local run history via @relavium/db — the RunStore writer + read API the gate-resume/list/logs/status surfaces consume), ✅ Done (PR #44, 2026-06-23) behind ADR-0050; and 2.C (the relavium provider commands — a provider registry + API keys in the OS keychain via @napi-rs/keyring, resolved keychain → RELAVIUM_<PROVIDER>_API_KEY env var → error), ✅ Done (PR #45, 2026-06-23) behind ADR-0019 + ADR-0006 (no new ADR — secrets.enc deferred past v1.0); and 2.E (the ink streaming TUI — the third RunRenderer over the one event bus: live per-node status

  • spinners, the active node's streaming tokens, a running cost footer, a persistent final summary; cooperative Ctrl-C cancel), ✅ Done (PR #46, 2026-06-24) behind ADR-0047 (ink + React 19, confined to apps/cli; no new ADR); and 2.G (the interactive human-gate prompt — a @clack/prompts card during run — plus the out-of-band relavium gate <runId> cross-process resume: reload snapshot → reconstruct checkpoint → resumeFromCheckpoint, idempotent, secret-input fail-closed), ✅ Done (PR #47, 2026-06-24) behind ADR-0047 (@clack/prompts; Node floor 20.11→20.12; no new ADR) — fully closing 2.K's deferred gate-resume half; and 2.I (the read commands list / logs / status / gate list over durable history — go/no-go #2, the read side; surfaces the pending gateIds the 2.G gate command points at), ✅ Done (PR #48, 2026-06-24) (no new ADR — an additive workflow-agnostic @relavium/db read seam + a @relavium/core parseAgent); and 2.L (packaging, distribution & install verification — go/no-go #7, the last gate-closing spine PR: the tsup engine-inlined ESM bundle, the bundle-closure drift guard, and the tag-triggered cross-OS install-smoke Release CLI workflow), ✅ Done (PR #49, 2026-06-24) behind ADR-0051closing go/no-go #7, so the Phase-2 spine is complete and all seven Phase-3 exit criteria now hold (Phase 3 may start). Also landed — the first additive lane: 2.S (media host-wiring — the surface half of the multimodal sub-spine: the model_catalog reader → resolveMediaSurface routing + the D15 catalog load-check shared by run/gate, the content-addressed MediaStore de-inline to a media:// handle, the SSRF-validated EgressCapability.fetch egress, the containment-checked save_to write port, durable fail-cost on the terminal events, the produced-media render surface, and the best-effort run-end host media GC), ✅ Done (PR #52, 2026-06-25) behind ADR-0042ADR-0046 (no new ADR). Also landed — the first user-facing AgentSession surface: 2.M (relavium chat — the agent-first interactive REPL over AgentSession: streaming tokens, tool-call annotations, the FS-scope tier + allowedCommands allowlist honored, git_commit denied; /exit / /cancel / an input-stream EOF / raw-mode Ctrl-C all end the session with exit code 4 — over ONE framework-free command core driving both an ink TTY app and a plain non-TTY line loop; a built-in default agent over [chat].default_model for a zero-config first run; durable per-turn persistence to the shared history.db that round-trips via reconstructSessionState; the ADR-0028 cost cap wired; model output + pasted input sanitized of terminal control sequences at the display boundary), ✅ Done (PR #54, 2026-06-26) — no new ADR (covered by ADR-0024, ADR-0047, ADR-0028, ADR-0050, ADR-0029). read_media input access (D12) — which 2.S had pointed at 2.M — was split into a dedicated, security-reviewed follow-up (maintainer-approved); the 2.M REPL shipped without it (tracked in deferred-tasks.md). Also landed — the rest of the agent-first chat family: 2.N (relavium chat-resume — reload + continue a persisted session over a shared REPL), 2.O (chat-list — over a new additive SessionStore.listSessions read seam), 2.P (chat-export + the in-REPL /export — session → .relavium.yaml scaffold, ADR-0026), and 2.Q (chat --json — a headless SessionEvent NDJSON driver — + the one-shot relavium agent run with a minimal in-house --fixture cassette for deterministic offline replay), all ✅ Done (PR #55, 2026-06-26)no new ADR — completing the agent-first CLI lane. (agent run --input is reserved/rejected until session {{ctx.*}} prompt interpolation lands — a tracked engine follow-up in deferred-tasks.md.) Also landed — 2.R (the inbound MCP client): agents now consume external MCP servers' tools across chat, run, and one-shot agent run. The @relavium/mcp foundation (the SDK-fenced package, the dependency-free JSON-Schema→Zod compiler, the fail-loud connect-all manager, the mcp_{server}_{tool} namespacing) is ✅ Done (PR #56, 2026-06-26), and the host wiring (chat/run/agent-run), the network transports (http/sse/ websocket) behind the SSRF pre-connect floor + the per-server allow_local_endpoint opt-in, named secrets via the isolated mcp-secret:* keychain namespace, the by-name ref registration form, and the real-spawn e2e are ✅ Done (PR #57, 2026-06-27) — behind ADR-0034, ADR-0052, and ADR-0053. It was off the M3 critical path and the Phase-3 go/no-go (capability without gating). Residual MCP hardening — the connect-by-validated-IP dialer, network header-auth, tool-list caching, mid-call abort propagation, and the stdio import-trust gate — is tracked in deferred-tasks.md. Also landed — 2.J (the YAML-authoring lifecycle), the last in-phase lane: relavium create (a @clack/prompts wizard scaffolding an agent or a minimal single-agent workflow, validated against the kind-appropriate @relavium/shared schema before write, dual-TTY-gated), relavium import <path> (schema- validated copy-in with project-global id uniqueness), and relavium export <id> (a portable copy re-serialized from the validated AST — canonical, comment-free, no provider key by construction), sharing one assertSlugAvailable cross-catalog guard, ✅ Done (PR #58, 2026-06-28)no new ADR (covered by ADR-0026/ADR-0047).

Phase 2 — CLI is feature-complete. Every in-phase workstream (2.A–2.S) is merged and the published CLI is cut as v0.1.1; M3 was reached at 2.K and the Phase-3 go/no-go held from 2.L. See the Phase 2 workstreams and the sequencing plan. The full status-aware history is the Remaining build order section (its queue is now empty).

Phase 2.5 — CLI Consolidation & Conversational Home has started. 2.5.A (the spine's secure base — a shared assembleToolEnv({ profile, fsScopeTier, workspaceDir }) factory wired into both the chat and workflow-run paths, the host-side fs (realpath+commonpath jail, read-only chat fail-close, single-fd O_NOFOLLOW/O_NONBLOCK reads) and process arms, the advertise-filter, EA1 tool_unavailable, and EA2 real failed-turn usage) is ✅ Done (PR #60, 2026-06-28), behind ADR-0055reaching milestone M2.5-1 (secure base). The egress/os arms, the project-tier extraRoots allowlist, and a write-capable chat are deferred to 2.5.E/ADR-0057 (tracked in deferred-tasks.md). 2.5.B (the bare-invocation Home) is ✅ Done (PR #61, 2026-06-29), behind ADR-0054 (Accepted): the TTY-gated bare relavium opens a read-only management strip (recent sessions/runs/agents + an "Attention required" section of pending human gates / failed runs) over a bounded, indexed history.db read seam, sitting above a live prompt that graduates into an in-process chat; rendered as a single ink tree (one useInput owner) with one SIGINT/SIGTERM lifecycle (clean Home exit 0; an external signal → the conventional 128+signo, 130/143; the in-Home chat's exit-4 consumed, never leaked) and bracketed paste (DECSET 2004), all while every non-interactive path keeps the byte-for-byte help + exit-0 meta-op (ADR-0049). Canonically homed in home.md. 2.5.C (the in-app command system) is ✅ Done (PR #62, 2026-06-30), behind ADR-0056 (Accepted): a curated two-registry model (the shell COMMAND_MANIFEST driving commander + --help --json

  • the executeCommand dispatch, vs the in-REPL REPL_COMMANDS driving a filterable / palette + slash commands in both the chat and the bare Home — no command in both); /help, the notice output channel, /workflows, /cost, and /doctor (fast tier: keychain/config/wired-tools; --deep: a redacted provider-key probe + a read-only MCP-status report — a security-review decision: it reports the live session's already-connected servers, never a fresh connect/spawn); plus the name + args slash dispatch and a context-aware footer hint-bar surfacing / for commands. Canonically homed in commands.md + chat-session.md. 2.5.E (chat modes + per-tool approval + mid-turn abort) is ✅ Done (PR #63, 2026-07-03), behind ADR-0057 (Accepted after the mandatory security review): the reseat-less mode system (ask / plan / accept-edits / auto on Shift+Tab + /mode), the fail-closed per-tool confirmAction floor ([y]/[a]/[n] + a session once/always cache), the Esc mid-turn abort (EA7), and the host arms closing the 2.5.A deferral — a write-capable fs tier + protected paths (refused in every mode incl. auto), the SSRF-hardened egress arm (shared with media), and the os arm (now a governed action class). Wired live into relavium chat, one-shot agent run, and the Home (each activates the regime before its first turn). Every step passed the mandated opus + Sonnet 5 loop plus the dedicated holistic security review (~50 findings fixed, 4 HIGH). A same-PR chat-UX follow-up also landed: a host tool EXECUTION failure on the interactive surface (a file-not-found READ) is fed back to the model to recover (recoverToolFailures, scoped to IDEMPOTENT tools via a stamped ToolExecutionError.recoverable; a governed / side-effecting failure stays fail-fast) plus a static secret-free tool_failed hint. With 2.5.E the CLI Consolidation spine (2.5.A → C, E) is complete. 2.5.D (chat input ergonomics) is ✅ Done (PR #64, merged 2026-07-03) — the first experience-arm workstream: the pure-ergonomics half (Ctrl+J multiline, ↑/↓ history + Ctrl+R reverse-search, readline motions, a shared cursor-bearing EditorState) plus the two data-moving affordances behind ADR-0061 (Accepted after a two-round maintainer security review): @-mention (dir-navigable file completion that reads through the SAME FsCapability read_file uses — jail + the expanded sensitive-read confidentiality floor
  • listing-gate + binary/size guards — and injects as UNTRUSTED, nonce-fenced, byte+line-bounded context) and !-shell (the additive AgentSession.runUserCommand — EA8 — routing !command through the one run_command boundary: enforcePolicy([chat].allowed_commands) BEFORE the mode-aware confirmActionspawn/shell:false; empty-default allowlist ⇒ ! inert, secure-by-default, with an actionable deny hint). Each of the 5 steps passed the mandated opus + sonnet adversarial-review loop, and the ADR-0061 mandatory security pass ran inside the step-4/5 loops (14 findings fixed across the two @-mention rounds; on the !-shell the opus + security pass confirmed 0 defects after adversarial verification, and the sonnet second pass caught a HIGH — a !-command in flight left no host-visible busy signal, so a message typed mid-command could crash the session — now fixed with a shellBusy input gate, plus a LOW type-hygiene fix). A post-implementation comprehensive review then refined the @/! presentation to a pending-attachment (chip) model (an inline @path marker + a read-only !-output preview, expanded into the SAME UNTRUSTED nonce-fenced frame only at submit — byte-identical model context, a clean prompt), and two follow-up review passes hardened the [chat] allowlist resolution (exact + glob arrays are now a coupled unit) and fixed a Backspace regression (ink reports the Unix physical Backspace as key.delete); all recorded in the ADR-0061 "Refined at implementation" append. 2.5.F (the ADR-0062 context commands) is ✅ Done (PR #65, merged 2026-07-05) behind ADR-0062: /clear (a host-level fresh-session swap across chat/chat-resume/Home, TTY-interactive only), the session:compacting "Summarizing…" moment event (amending ADR-0036), and the footer context-fullness indicator — completing compaction alongside the earlier /compact + /trim + automatic compaction. 2.5.G (onboarding wizard + Home /models + the live model catalog) is ✅ Done (PR #66, 2026-07-07) — its scope expanded to Option A: a live model catalog (per-key provider discovery + a DB cache + refresh + a static/live merge) and a complete model-pricing story (user-supplied pricing that governs cost), behind three ADRs (ADR-0063 config-write · ADR-0064 live catalog · ADR-0065 provider economics), across 12 reviewed steps (all landed); with it milestone M2.5-2 is reached. The additive lane 2.5.H (reasoning render + live-turn feedback + an actionable error taxonomy) is ✅ Done (PR #67, 2026-07-07) — behind EA6 (a new dual-envelope agent:reasoning stream event that amends ADR-0036; no new top-level ADR): a host-emit of the reasoning the @relavium/llm seam already carries (ADR-0030), a collapsible "thinking" panel (/thinking / Ctrl+T), the Thinking…/Working… {elapsed}s · Esc to stop timer, a visible elision marker (fixing the silent live-buffer head-drop), per-attempt via {model} failover attribution, and a static, secret-free per-ErrorCode recovery hint (session-survives; a context-overflow message heuristic → /compact· /trim). Four steps, each opus + Sonnet reviewed (3 HIGH fixed: a run-path silent-drop, a frozen Home timer, a scrollback elision loss; + a one-shot agent run hint-leak). With 2.5.E this reaches milestone M2.5-3. The consolidation lanes 2.5.I (regression harness + DB concurrency hardening — loadFull read-txn snapshot, BEGIN IMMEDIATE writes with a deterministic SQLITE_BUSY retry, the concurrent chat+run + cassette-chain + perf-budget e2es, an advisory Windows CI lane) and 2.5.J (docs-debt: the accurate unencrypted-history posture per ADR-0050, and NO_COLOR/FORCE_COLOR/--color resolution) are ✅ Done (2.5-close-out, PR #69, 2026-07-08)reaching milestone M2.5-4, so Phase 2.5 is complete, merged to main — landed alongside the doable-now Batch A–E backlog (test-hardening; 2.5.H TUI polish; AgentParseError line/col; the ADR-0057 approval/security batch — [c] reject-with-reason, non-TTY policy, SCOPE-denial recovery, Ctrl+T-in-approval, the Trojan-Source bidi floor, behind an append-only ADR-0057 amendment; the profile-aware advertise-filter + the in-house .gitignore matcher), each implement → Opus → Sonnet with a security-review pass on the approval batch. Two gate.ts-resume items (relavium budget resume + secret re-provide) are deferred to a focused follow-up, and the session {{ctx.*}} interpolation stays with the Proposed ADR-0060 (Phase-2.6); all tracked in deferred-tasks.md. See the Phase 2.5 workstreams. A post-2.5.G model-UX follow-up (from six maintainer questions on model/provider/wizard behavior) then landed as a sequenced plan: /models key-awareness, the onboarding-wizard live key-validation + retry UX, wizard-dynamic provider docs, mid-session model switching (the /models reseat across relavium chat + the in-Home chat — ADR-0059, now Accepted), and normalized reasoning-effort control (ADR-0066, now Accepted, merged 2026-07-07): a provider-agnostic effort tier (off/low/medium/high/max) authored in agent YAML or the [chat].reasoning_effort config default, each adapter mapping it to its provider's native tier — all four providers, DeepSeek-v4's thinking param included (doc-verified against api-docs.deepseek.com) — gated per-model by a host-injected capability resolver (plus a conservative id heuristic for a live-discovered model). It is changed interactively: /effort opens a keyboard-owning tier-selector overlay in relavium chat + the in-Home chat (§6), and the /models picker's effort sub-step either applies a per-turn session override in a live chat (no reseat, §5) or — in the bare Homewrites the model + effort as the next session's config defaults (a new global [preferences].reasoning_effort key), the active tier shown in the footer. Two multi-agent review passes hardened it: the first caught the picker (wrongly) routing effort through a full model reseat — the P0 fix rebuilt it as the ADR-mandated session-level setter; the second caught the bare-Home effort default not being re-read for a same-process next chat — fixed to mirror the model's fresh per-chat re-read.

Carry-over hardening is tracked in deferred-tasks.md — Phase 2 picks items up as it first touches each file. Notable inheritances: 1.AH's host-wiring half (distributed across Phases 2–6), the media-egress host-side SSRF mechanism, and the keychain no-raw-key IPC test.

Not started yet

The rest of Phase 2.6 — Conversational Authoring and the First-Class CLI (phase-2.6-conversational-authoring.md, in progress — 2.6.F is done, unblocked by the 2.5 close and re-scoped 2026-07-08 from maintainer UX findings + a competitor research pass + the deferred-tasks triage): a full-screen, Home-managed CLI (browsers for workflows/runs/agents, provider + MCP + settings management, onboarding v2 with the Relavium-account stub), competitor-breadth tools under the governance floor, settings/theming/en+tr localization, the run-ops resume follow-up — plus the original spine: the shared @relavium/authoring package and a chat that authors standards-valid .relavium.yaml. Then the surfaces and the cloud — everything after the engine critical path: the desktop app (Phase 3) and the VS Code extension (Phase 4), then Product Phase 2 — first managed inference (phase-5-managed-inference.md, the opt-in managed gateway, engine still local), then the cloud execution layer and web portal (phase-6-cloud-execution-portal.md), the two decoupled per Option B. See the phase index and the milestone spine (M3 onward).