Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 34 additions & 28 deletions docs/roadmap/current.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ pending a Gemini pricing decision.

**The unified build order across both phases is in
[Execution order — Phase 2.5.5 + Phase 2.6](#execution-order--phase-255--phase-26-temporary) below** — a
temporary section, deleted when both phases close. Short version: **merge PR #76 first**, because Phase
2.5.5's whole backlog is written against `f88b0e8`, which lives only on `development`.
temporary section, deleted when both phases close. Its baseline step is discharged (PRs #76 and #77 merged);
**the next unit of work is Wave 0's single `ci.yml`/`turbo.json`/`tsup.config.ts` PR.**

## Execution order — Phase 2.5.5 + Phase 2.6 (temporary)

Expand All @@ -46,25 +46,25 @@ temporary section, deleted when both phases close. Short version: **merge PR #76
> Derived 2026-07-26 from a full pass over both phase files, their own sequencing sections, and the live
> tree. Where it departs from a phase file's own prose, see [Departures](#departures-from-the-phase-files-own-sequencing).

### Ordering root — collapse to one baseline before anything else
### Ordering root — one baseline ✅ **discharged 2026-07-26**

Verified against the live tree on 2026-07-26, and stated in neither phase file:
The plan opened on a divergence neither phase file modelled: Phase 2.5.5's whole backlog is written against
`f88b0e8`, which existed only on `development` behind PR #76, so every `file:line` citation in it resolved
against a tree nobody was branching from. **PR #76 and #77 are both merged** — `f88b0e8` is on `origin/main`,
`origin/development` and `origin/main` hold identical trees, and there are no open PRs. Every citation in
this plan now resolves.

| Fact | Value |
|------|-------|
| `development` vs `origin/main` | **64 commits ahead, 0 behind** |
| Where `f88b0e8` (the 2.5.5 review baseline) lives | **`development` only — not on `main`** |
| Open PRs | **#76** (`development` → `main`) — the only one |
| Local `main` vs `origin/main` | **126 commits behind** |
One consequence survives and is worth keeping until the phases close:

Phase 2.5.5's entire backlog is written against `f88b0e8`. Until PR #76 merges, every `file:line`
citation in it resolves against a tree nobody branches from, the three picker bugs and the param-rejection
self-heal are invisible from `main`, and `a10f37b` — landed *after* the 2026-07-19 review and therefore
unreviewed by it — silently invalidates the premise of 2.5.5.B's `#emitSuccess` catch-narrowing item and
part of the adapter-parity sweep.
> **Branch from `origin/development`, never from a local `main`.** A long-lived `development` merged into
> `main` by merge commit leaves a stale local `main` behind after every PR, silently and without conflict.
> Run `git fetch` and cut from `origin/development`.

**Start here: merge PR #76.** Then publish the rule *branch from `origin/development`, never local `main`* —
local `main` contains neither 2.6.F nor 2.6.C.
Also settled while discharging this: `main` now carries branch protection (PR required, `lint · typecheck ·
test` required, force-push and deletion blocked) and a `v*` tag ruleset restricting tag creation to the
maintain/admin roles — closing the Phase-0 obligation that made `ci.yml`'s own "REQUIRED status check"
comment untrue. `release.yml` asserts its ref is reachable from `main` before `pack`, so **2.5.5.H's `G26`
is closed ahead of Wave 0**.

### The three axes this order is built on

Expand All @@ -82,7 +82,7 @@ any order"* — never as headcount.

```mermaid
flowchart TD
W0["Wave 0 — One true baseline<br/>PR #76 · CI truth · numbers"]
W0["Wave 0 — One true baseline<br/>baseline ✅ · CI truth · numbers"]
W1["Wave 1 — Stop the bleeding<br/>3 CRITICALs · cost cap"]
W2["Wave 2 — Shut the doors<br/>MCP · fs jail · secrets<br/>certifies 2.5.5 EXIT 1–3"]
W3["Wave 3 — Clear the ground<br/>god-file decomposition · CLI net"]
Expand All @@ -103,23 +103,27 @@ flowchart TD
Collapse the divergence, make the required gate execute the artifact it ships, and fix the review
checklists before ~30 security-gated PRs are reviewed against them.

1. **Merge PR #76** (carries 2.6.Q P1–P5, ADR-0071/0072, the three picker bugs, the param self-heal).
1. ✅ **Merge PR #76** (2.6.Q P1–P5, ADR-0071/0072, the three picker bugs, the param self-heal) — **done
2026-07-26**, along with #77 (this plan + the Phase-2.5.5 opening + `release.yml`'s `G26` ancestry gate).
2. **Reserve numbers**, one per number in landing order — migrations end at `0012` and ADRs at `0072`
(verified): `0013` = the Wave-1 approval-preview scrub · `0014` = 2.5.5.C's enum CHECKs (#101) ·
`0015` = 2.6.H · `0016` = 2.6.G's pins · `0017` = 2.6.N lineage; **ADR-0073+** for the nine unwritten 2.6 ADRs.
3. **One `ci.yml`/`turbo.json`/`tsup.config.ts` PR** (a five-way collision file — do not split):
2.5.5.H · the required gate never runs the compiled binary + undeclared `drizzle` output (#294, #315) →
local `pnpm ci` vs `ci.yml` divergence (#312) → the coverage-floor **ruling and its implementation**
(#296, #152) → the `(advisory)` labels (#320) → `THIRD_PARTY_EXTERNAL` (G27, #248) → bundle-closure
single-chunk assert (#314) → `release.yml`'s in-workflow ancestor check (G26) → `sync:models:check` (#317).
single-chunk assert (#314) → `sync:models:check` (#317). *(`release.yml`'s ancestry check, `G26`, already
landed in #77; only its tag-protection half remains, and that is now configured too.)*
4. 2.5.5.F · **three skills' hardcoded foreign-project paths** (#162) — filed as docs, actually a functional
bug: they write outside the repo.
5. **One markdown PR** (shared files): `packages/mcp` missing from five inventory tables (#128, #129, #153,
#163, #254) + the two review-checklist gaps (#164, #167) + the CLAUDE.md/README i18n clause (#74, #260, #134).
6. The **locale-bar amendment** (decision D5) and the **snapshot regen** after the Gemini price ruling (D3).

> Why first: nothing lands cleanly around a 64-commit divergence, and every wave after this adds a
> migration. The coverage gate must flip *before* ~120 items land, not mid-flight.
> Why first: every wave after this adds a migration, and the required gate still does not execute the
> binary it ships while turbo does not declare `apps/cli/drizzle/**` as a build output — so a cache-hit
> replay can leave `dist/index.js` fresh beside a stale `drizzle/`, crashing on first DB touch. The
> coverage gate must also flip *before* ~120 items land, not mid-flight.

### Wave 1 — Stop the bleeding

Expand Down Expand Up @@ -288,7 +292,7 @@ Exit criterion 2: no routine task requires a shell subcommand.

### Wave 6 — Hands, voice and lineage

Exit criteria 3 and 4, plus the child-session foundation — so the riskiest wave does not also carry its
Phase-2.6 go/no-go criteria 3 and 4, plus the child-session foundation — so the riskiest wave does not also carry its
lineage work.

1. **ADR row 9** (toolbelt + tool-render/approval-preview contract + `ask_user`'s mid-turn engine pause)
Expand All @@ -300,7 +304,7 @@ lineage work.
`/rewind`-vs-child-sessions moves to Wave 7 (it gates on 2.6.N).
4. **ADR row 12** (child-session foundation) → **2.6.N's foundation**: lineage, standardized I/O, the
injected artifact-store port, catalog spawn, the depth-3/concurrency-5 guardrails.
5. **Certify exit criteria 3 and 4 here**, not in Wave 7 — `invoke_agent` gates only on 2.6.N, which lands here.
5. **Certify Phase-2.6 go/no-go criteria 3 and 4 here**, not in Wave 7 — `invoke_agent` gates only on 2.6.N, which lands here.

### Wave 7 — Orchestration and the gate

Expand Down Expand Up @@ -361,7 +365,8 @@ unanswered**; the remainder sit inline in their own phase-file bullet.
This ordering is compatible with both phase files' stated dependencies. It departs from their prose in six
places, each deliberate:

1. **A baseline step neither file has.** Both treat `f88b0e8` as the working tree; it is not on `main`.
1. **A baseline step neither file has.** Both treated `f88b0e8` as the working tree while it was not yet on
`main`. Discharged 2026-07-26; kept here because it is why Wave 0 exists at all.
2. **2.5.5's recommended order is A+C → D+I → E → B+H → F+G.** This keeps its risk instinct but re-cuts the
batches by **file**, because ~40 files are edited by both a 2.5.5 item and a 2.6 item. Sub-stream letters
are filing conventions, not batching units — every split above is declared.
Expand All @@ -388,9 +393,10 @@ plumbing + inline & async output generation + generative adapters, 1.m6, 1.AD–
[Phase 1 detail](phases/phase-1-engine-and-llm.md), the [decision index](../decisions/),
and the [reference specs](../reference/).

> **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
> **Live maintainer obligations:** (1) ✅ **done 2026-07-26** — the CI `ci` job is now a **required check**
> under branch protection on `main` (PR required, force-push/deletion blocked), alongside a `v*` tag ruleset
> limiting tag creation to maintain/admin; the optional `TURBO_TOKEN`/`TURBO_TEAM` secrets for the
> cross-runner remote cache are still unset; (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](../decisions/0051-cli-distribution-thin-bundle-private-engine.md) /
Expand Down
2 changes: 1 addition & 1 deletion docs/roadmap/deferred-tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -1232,7 +1232,7 @@ future test cannot silently re-acquire it.
> **2026-07-19 — full-project review.** A 377-finding multi-agent code review at HEAD `f88b0e8` was
> adversarially verified down to 373 confirmed findings — one agent per finding tried to refute it against
> the code, a second audited its materiality — with the toolchain green throughout (lint, typecheck, all 226
> test files passing): every finding below is a defect a green build cannot catch. The bulk (205 work items)
> test files passing): every finding below is a defect a green build cannot catch. The bulk (176 of the 205 triaged work items)
> now live in [phases/phase-2.5.5-hardening-and-remediation.md](phases/phase-2.5.5-hardening-and-remediation.md).
> Sixteen of the review's findings turned out to duplicate items already recorded in this file — each already
> carries an accurate `Scheduled →` marker (2.6.B/2.6.H/2.6.I/2.6.K/2.6.M/2.6.Q) or an accurate "no owner yet"
Expand Down
72 changes: 50 additions & 22 deletions docs/roadmap/phases/phase-2.5.5-hardening-and-remediation.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,14 @@ completing first — each is centred on its own subsystem (`packages/core`, `pac
`packages/db`, `packages/mcp` + secrets, `apps/cli`'s process layer, `apps/cli`'s TUI layer,
`docs/`, cross-cutting hygiene, and the CI/tooling substrate). The sub-streams are **not**,
however, fully file-disjoint, so "any order" holds between disjoint queues rather than across
the phase as a whole. Two overlaps are known and must be serialized rather than run in parallel:
the phase as a whole. Ownership is not pairwise: `home-controller.ts` and `chat.ts` are each edited
from **four** sub-streams (E, F, G and I), `chat-ink.tsx` from three (E, G, I), and `viewport.ts` and
`client.ts` from two each. The operative rule that falls out is short — **2.5.5.I lands last on every
god-file**, because its work is decomposition and everything else is edits that decomposition would
otherwise have to re-apply. The five bullets below record the landing order for the overlaps the review
surfaced; they are not a proof of completeness, so the standing discipline is to **compare the file list
in a bullet's `(S/M/L · files · findings)` trailer against the other sub-streams before parallelizing
anything**:

- **2.5.5.C ↔ 2.5.5.E on `packages/db/src/client.ts`** — C gives `createClient` a typed error and
corrects its PRAGMA docstring (`#104`, `#105`); E moves the wrap-and-redact logic inside
Expand All @@ -68,6 +75,14 @@ the phase as a whole. Two overlaps are known and must be serialized rather than
`const exhaustive: never` sweep (`#300`, `#301`, `G3`); I decomposes `createHomeController`
(`#215`, `#243`) and applies the min-terminal-size guard (`#63`). **E's items land first**, so the
decomposition moves already-guarded code.
- **2.5.5.F ↔ 2.5.5.I on `home-controller.ts`** — F wires Home's `showCost` past its no-op (`#125`),
which edits a line *inside* the function I dissolves (`#215`, `#243`). **F lands first.**
- **2.5.5.G ↔ 2.5.5.I on `apps/cli/src/commands/chat.ts`** — G replaces the hand-rolled money helpers
(`#236`, `#307`) and renames `swapAgentModel` (`#218`); I decomposes the file (`#220`, `#244`).
**G lands first**, so the decomposition moves already-canonical code.
- **2.5.5.G ↔ 2.5.5.I on `apps/cli/src/render/tui/viewport.ts`** — G makes width measurement
tab-aware (`#65`); I caches per-cluster widths and debounces resize invalidation (`#64`, `#66`).
Both rewrite `graphemeWidth`. **G lands first**, so the cache is built over the corrected measure.

Everything else may proceed concurrently. The cross-phase file-ownership preferences are separate
and are called out under [Positioning](#positioning).
Expand All @@ -85,8 +100,14 @@ reached.
(`#91`, `packages/core/src/tools/registry.ts`'s `previewFor()`), the chat persister's
unhandled-promise-rejection crash path (`#228`, `apps/cli/src/chat/persister.ts`), and the
unsanitized `relavium run` TUI (`#56`, `apps/cli/src/render/tui/RunApp.tsx`) — are closed and
regression-tested. `#56` lands with 2.5.5.I rather than 2.5.5.A/C, so it certifies under
M2.5.5-2; the severity is the traceability appendix's own, not a reclassification.
regression-tested. `#56` lands with 2.5.5.I rather than 2.5.5.A/C, so it certifies under M2.5.5-2.
> **`#56`'s severity is contested and needs a maintainer ruling.** The traceability appendix below —
> the only classification that ships in git — records it `critical`, and this file follows it. The
> untracked review corpus's executive summary argues the corpus's real critical count is **2**, on the
> grounds that `#56`'s verifier recommended `high` and the aggregate severity field never picked the
> correction up. Nothing downstream changes either way: `#56` is scheduled in Wave 1 and gated by exit
> criterion 2's security review regardless. Rule it once, then make the appendix, the exec summary and
> this bullet agree.
- `relavium run`'s TUI, the persisted run summary, the universal error boundary, and the
human-gate approval card all sanitize dynamic/model-controlled text the same way chat
already does — a security review confirms the injection class is closed.
Expand Down Expand Up @@ -421,33 +442,40 @@ This substream is the development-process substrate itself — `.github/workflow

All nine sub-streams are independent (`dependsOn` is empty on every one) — no sub-stream must
complete before another starts. They are **not** all file-disjoint, though, so concurrency runs
between disjoint queues rather than across the phase as a whole: the two known overlaps
(2.5.5.C ↔ 2.5.5.E on `packages/db/src/client.ts`, and 2.5.5.E ↔ 2.5.5.I on
`home-controller.ts`/`chat-ink.tsx`) carry a required landing order, recorded under
[Positioning](#positioning). The order below is a value/risk recommendation, not a dependency
between disjoint queues rather than across the phase as a whole: the five known overlaps — on
`packages/db/src/client.ts`, `home-controller.ts`/`chat-ink.tsx`, `chat.ts` and `viewport.ts` —
each carry a required landing order, recorded under [Positioning](#positioning). The order below is a value/risk recommendation, not a dependency
chain, leading with safety-critical work:

1. **2.5.5.A and 2.5.5.C first** — each contains one CRITICAL, self-contained defect (the
approval-preview secret leak; the chat-persister crash) with a small, well-understood
blast radius. Land these before anything else touches the same files.
2. **2.5.5.D and 2.5.5.I next** — both close CRITICAL/live security gaps with no existing
coverage (MCP tool-definition poisoning, the config-layer secret hijack, terminal-control
injection into `relavium run`). Within 2.5.5.I, the `chat.ts`/`home-controller.ts`
decompositions are the one item worth sequencing deliberately: land them **before** Phase
2.6's **2.6.G** and **2.6.E** add substantial new code to either file, to avoid a large,
conflict-prone rebase later. This is a cross-phase file-ownership preference, not a
2.5.5-internal dependency.
3. **2.5.5.E** — the broadest user-facing surface (every command passes through it), best
landed once the engine/data/security fixes above are stable under it.
2. **2.5.5.D next** — it closes CRITICAL/live security gaps with no existing coverage (MCP
tool-definition poisoning, the config-layer secret hijack), and it shares no file with any
other sub-stream.
3. **2.5.5.E, then 2.5.5.I** — in that order, not the reverse. E is the broadest user-facing
surface (every command passes through it) and is best landed once the engine/data/security
fixes above are stable under it; I's decompositions must then move already-guarded,
already-canonical code, per the overlap rules above. Two carve-outs: I's terminal-control
sanitization item (`#56`, `G34`, `G44`, `#57`) is a CRITICAL sharing no file with E's queue, so it is
pulled ahead alongside step 1; and the four **step-5 items that collide with I** — F's `showCost`
wiring (`#125`) and G's `chat.ts`/`viewport.ts` items (`#236`, `#307`, `#218`, `#65`) — are pulled
**forward to here**, ahead of I, rather than waiting for step 5. Within I, the `chat.ts`/`home-controller.ts` decompositions
additionally want to land **before** Phase 2.6's **2.6.G** and **2.6.E** add substantial new code
to either file, to avoid a large, conflict-prone rebase later — a cross-phase file-ownership
preference, not a 2.5.5-internal dependency.
4. **2.5.5.B and 2.5.5.H** — money-correctness and process-substrate hardening; neither is
time-critical, both benefit from the same shared-fixture-per-guard discipline the security
items above establish.
5. **2.5.5.F and 2.5.5.G** — documentation accuracy and codebase hygiene; zero runtime risk,
safe to run last or interleaved with any of the above at any point.

The three items with an explicit cross-phase preference (the two 2.5.5.I decompositions, and
the authoring run-path tool-preflight item filed directly as a 2.6.A work item) are the only
sequencing constraints in this phase; everything else is scheduler's choice.
5. **2.5.5.F and 2.5.5.G** — documentation accuracy and codebase hygiene; zero runtime risk, safe to
interleave anywhere. Minus the four items pulled forward into step 3 (F's `#125`; G's `#236`,
`#307`, `#218`, `#65`), which must precede 2.5.5.I on the files they share.

Two constraint sets bind, and nothing else does. **Cross-phase:** the three items with an explicit
preference (the two 2.5.5.I decompositions, and the authoring run-path tool-preflight item filed
directly as a 2.6.A work item). **Intra-phase:** the five file overlaps recorded under
[Positioning](#positioning) (`client.ts`, `home-controller.ts`/`chat-ink.tsx`, `chat.ts`,
`viewport.ts`). Everything outside those two sets is scheduler's choice.

## Dependencies

Expand Down
Loading
Loading