From 34a3f5f72add681232fac2d13f56a17b92812079 Mon Sep 17 00:00:00 2001 From: Cemil ILIK Date: Sun, 26 Jul 2026 10:54:22 +0300 Subject: [PATCH 1/2] docs(roadmap): update execution order and clarify dependencies for Phase 2.5.5 and 2.6; enhance input normalization in authoring wizards --- docs/roadmap/current.md | 62 +++++++++-------- docs/roadmap/deferred-tasks.md | 2 +- .../phase-2.5.5-hardening-and-remediation.md | 68 +++++++++++++------ .../phase-2.6-conversational-authoring.md | 46 +++++++------ 4 files changed, 107 insertions(+), 71 deletions(-) diff --git a/docs/roadmap/current.md b/docs/roadmap/current.md index ccf0a236..7ecc5d59 100644 --- a/docs/roadmap/current.md +++ b/docs/roadmap/current.md @@ -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) @@ -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 @@ -82,7 +82,7 @@ any order"* — never as headcount. ```mermaid flowchart TD - W0["Wave 0 — One true baseline
PR #76 · CI truth · numbers"] + W0["Wave 0 — One true baseline
baseline ✅ · CI truth · numbers"] W1["Wave 1 — Stop the bleeding
3 CRITICALs · cost cap"] W2["Wave 2 — Shut the doors
MCP · fs jail · secrets
certifies 2.5.5 EXIT 1–3"] W3["Wave 3 — Clear the ground
god-file decomposition · CLI net"] @@ -103,7 +103,8 @@ 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. @@ -111,15 +112,18 @@ checklists before ~30 security-gated PRs are reviewed against them. 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 @@ -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) @@ -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 @@ -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. @@ -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) / diff --git a/docs/roadmap/deferred-tasks.md b/docs/roadmap/deferred-tasks.md index 0cb9789b..dc5138cb 100644 --- a/docs/roadmap/deferred-tasks.md +++ b/docs/roadmap/deferred-tasks.md @@ -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" diff --git a/docs/roadmap/phases/phase-2.5.5-hardening-and-remediation.md b/docs/roadmap/phases/phase-2.5.5-hardening-and-remediation.md index e0185b07..61eafa5a 100644 --- a/docs/roadmap/phases/phase-2.5.5-hardening-and-remediation.md +++ b/docs/roadmap/phases/phase-2.5.5-hardening-and-remediation.md @@ -57,7 +57,10 @@ 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. Five overlaps are known today and must be serialized rather than run in +parallel — the three god-files each draw two sub-streams, and the general rule is to **compare the +file list in a bullet's `(S/M/L · files · findings)` trailer against the other sub-streams before +parallelizing anything**, since this list is what the review surfaced, not a proof of completeness: - **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 @@ -68,6 +71,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). @@ -85,8 +96,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. @@ -421,33 +438,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 diff --git a/docs/roadmap/phases/phase-2.6-conversational-authoring.md b/docs/roadmap/phases/phase-2.6-conversational-authoring.md index 4de0e728..adcc6b08 100644 --- a/docs/roadmap/phases/phase-2.6-conversational-authoring.md +++ b/docs/roadmap/phases/phase-2.6-conversational-authoring.md @@ -164,7 +164,8 @@ the same core. `nodeCatalogIssue` reads a node-level model *override* but never the resolved agent's own `model:`, so the catalog pre-flight is silently dead for the canonical, documented authoring pattern — declaring the model once on the `agents:` block. Fix early in this workstream, since the acceptance criterion - ("`create` runs the same catalog pre-flight as `run`") depends on this function being correct. + ("`create`, `import` and `export` all run the same run-equivalent catalog pre-flight") depends on this + function being correct. *(M · `packages/core/src/validate-catalog.ts`; #88)* - **Run-path tool pre-flight for the unwired egress/os arms:** `build-engine.ts` always assembles the tool host at `profile: 'workflow-read-write'`, and `assemble.ts`'s `wireEgressOs` only wires @@ -184,16 +185,18 @@ the same core. today `max_tokens` is validated only as a bare positive int and an over-ceiling value 400s opaquely at the wire. Leave an unknown-ceiling model (custom `base_url`) as pass-through. No new ADR (rides ADR-0058). -- Add direct unit tests for `detectAndParse` / `buildAuthored` / `validateAuthoredWorkflow` (today only the - command wrappers are tested). Confirmed by the review as a real coverage gap in the core this workstream - extracts. *(M · `apps/cli/src/authoring/authoring.ts`; #6)* +- Add direct unit tests for `detectAndParse` / `buildAuthored` — today only their command wrappers are + tested — and for the new `validateAuthoredWorkflow` this workstream introduces (it does not exist yet; + only its `validateWorkflowWithCatalog` half ships today). Confirmed by the review as a real coverage gap + in the core this workstream extracts. *(M · `apps/cli/src/authoring/authoring.ts`; #6)* **Acceptance:** `@relavium/authoring` builds and imports **only** `@relavium/core` + `@relavium/shared` (lint-fence enforced); the CLI consumes it with `create`/`import`/`export` round-tripping **unchanged** (regression-tested); **all three of `create`, `import` and `export`** run the same run-equivalent catalog -pre-flight (`validateAuthoredWorkflow` = `parseWorkflow` + `validateWorkflowWithCatalog`) that -`relavium run` uses, so no authoring entrypoint can accept a file the run path rejects; the core is -directly unit-tested. **Required ADR:** [ADR-0058](../../decisions/0058-relavium-authoring-package-and-conversational-authoring.md) +pre-flight (`validateAuthoredWorkflow`, defined in the task above) that `relavium run` uses, so no authoring +entrypoint can accept a **workflow** the run path would reject; the core is directly unit-tested. (All three +commands also accept `.agent.yaml` via `detectAndParse` → `parseAgent`; catalog pre-flight is +workflow-shaped, so an agent file stays parse-validated only — a deliberate scope line, not an oversight.) **Required ADR:** [ADR-0058](../../decisions/0058-relavium-authoring-package-and-conversational-authoring.md) (Proposed → Accepted when this workstream begins). ### 2.6.B — Conversational + wizard authoring in the Home @@ -216,19 +219,22 @@ deferred items. - **In-Home authoring wizards**: bring `relavium create`'s wizard into the Home/chat palette (`/create` → an ink-native agent/workflow wizard over the same injectable prompter seam), so authoring starts from the Home, not only from a shell command. -- **Wizard TTY prompts don't normalize input** *(review finding):* `create-prompter.ts`'s TTY prompts pass - typed values straight through with no `.trim()`, so accidental leading/trailing whitespace silently - corrupts an authored value. Fix per field rather than blanket-trimming, in the same prompter seam this - task brings into the Home's `/create` wizard: - - **`slug`** — trim, then **reject** any value still carrying whitespace with a field-named message. - A blanket trim would silently accept `my agent` (interior space), which the schema rejects later and - further from the typo. - - **`name`** — trim; a leading/trailing space is never meaningful in a display name. - - **`description`** — trim leading/trailing whitespace but preserve interior formatting, so a - deliberately multi-line description round-trips unchanged. - - Cover each policy with a prompter test, including the boundary cases: whitespace-only input, interior - whitespace in a slug, and a multi-line description. *(S · `apps/cli/src/authoring/create-prompter.ts`; #5)* +- **Wizard TTY prompts don't normalize input** *(review finding):* `create-prompter.ts`'s free-text prompts + return the typed value verbatim, so accidental leading/trailing whitespace reaches `CreateSpec`. Fix per + field rather than blanket-trimming, in the same prompter seam this task brings into the Home's `/create` + wizard. `gather()` collects `kind`, `name`, `provider`, `model`, `systemPrompt` and `tools`; the three + free-text fields are: + - **`model`** — the material case: trim, and **reject** a value still containing interior whitespace, since + a model id is a single token. A trailing space breaks catalog lookup and currently 400s at the wire. + - **`name`** — trim. It feeds both the display name and `toSlug()`. + - **`systemPrompt`** — trim leading/trailing, preserve interior formatting so a multi-line prompt + round-trips unchanged. + + Two guarantees already hold and must not be re-implemented: `required()` rejects whitespace-only input for + every field, and `tools` is already trimmed per element. `toSlug()` also already normalizes whitespace + (`my agent` → `my-agent`), so there is no slug prompt to police. Cover each policy with a prompter test, + with interior whitespace in `model` and a multi-line `systemPrompt` as the boundary cases. + *(S · `apps/cli/src/authoring/create-prompter.ts`; #5)* - **`AgentParseError` reaches the chat surfaces** *(deferred pull-in)*: a malformed `.agent.yaml` on `chat --agent` / `agent run` currently collapses to a generic exit-1 internal error; resolve the design call (wrap into `CliError('invalid_invocation')` at `resolveChatAgent`, or teach the top-level renderer From 27d55413a6ba58e7e52bf9437e6a992744b1df9f Mon Sep 17 00:00:00 2001 From: Cemil ILIK Date: Sun, 26 Jul 2026 11:38:14 +0300 Subject: [PATCH 2/2] docs(roadmap): clarify ownership and landing order for overlapping sub-streams in Phase 2.5.5 --- .../phases/phase-2.5.5-hardening-and-remediation.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/roadmap/phases/phase-2.5.5-hardening-and-remediation.md b/docs/roadmap/phases/phase-2.5.5-hardening-and-remediation.md index 61eafa5a..f4bd07de 100644 --- a/docs/roadmap/phases/phase-2.5.5-hardening-and-remediation.md +++ b/docs/roadmap/phases/phase-2.5.5-hardening-and-remediation.md @@ -57,10 +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. Five overlaps are known today and must be serialized rather than run in -parallel — the three god-files each draw two sub-streams, and the general rule is to **compare the -file list in a bullet's `(S/M/L · files · findings)` trailer against the other sub-streams before -parallelizing anything**, since this list is what the review surfaced, not a proof of completeness: +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