merge: wave 1 order 3 (plan and design) into main

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-10-06 20:36:31 +02:00
commit 885d515c3b
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
24 changed files with 3115 additions and 61 deletions

View file

@ -0,0 +1,114 @@
<!--
The design part of a plan (plan_version 1.8). /trekplan Phase 8 writes it as
the plan's `## Design` section, between `## Context` and
`## Implementation Plan`, ONLY when the brief's `ceremony:` is
`architectural` (an absent field means architectural: heaviest on doubt).
`small` and `bounded` plans omit it.
The design lives in the PLAN, never in the brief: the brief format is a public
contract (Handover 1), the plan contract is Voyage's own (Handover 4).
`plan-validator --strict` checks, for an architectural 1.8 plan: the eight
`###` subsections below exist, the module map is a mermaid graph with no
cycle, every architecture rule names its enforcer, a checked rule names the
step that proves it, and an advisory rule names its `.claude/rules/` file.
`### Decisions (ADR)` and `### Gotchas` are optional.
Borrowed, with credit:
- Section list: Kiro's design.md (architecture, data flow, interfaces, data
models, error handling, test strategy), and its requirements analysis asked
as two-choice questions. Kiro's SMT engine is not borrowed.
- Design questions: obra/superpowers@8ca22db brainstorming (MIT, © 2025 Jesse
Vincent).
- Module map with one dependency direction and no cycles, and "use the
de-facto tool" (e.g. dependency-cruiser): addyosmani/agent-skills@9d0c60d
(MIT, © 2025 Addy Osmani).
- Vocabulary (deep module, seam, deletion test), the three-condition ADR bar,
and pass → fail → pass: mattpocock/skills@c55ee46 (MIT, © 2026 Matt Pocock).
- Rules that must pass: GitHub Spec Kit's constitution (MIT), changed so each
rule names what enforces it; in Spec Kit the model ticks the boxes itself.
- Gotchas and "Derived from <hash>": bashebr/ai-native-sdlc@11fb8d7 (MIT).
-->
## Design
> Derived from: `{brief path}` @ sha256 `{first 12 hex of the brief's sha256}` · ceremony: architectural
### Architecture
The modules this change adds or alters, and what each one owns. Judge each by
the deletion test: if deleting the module would only move its complexity into
its callers, it earns its place; a deep module hides much behind a small
interface. Name the seams where behaviour can be tested or swapped.
### Data Flow
How data enters, moves through and leaves the changed modules — one path per
use case in the brief, in order.
### Interfaces
Every boundary this plan creates or changes: signature, inputs, outputs,
errors. Steps cite these in `Interface in:` / `Interface out:`.
### Data Models
Types, schemas, files and their fields. Mark what is new and what changes shape.
### Error Handling
Each failure mode, what the system does about it, and what the user sees.
Unreadable input, a missing dependency and a partial failure are always listed.
### Module Map
Dependencies point one way. The validator rejects a cycle.
```mermaid
graph TD
cli[src/cli] --> core[src/core]
core --> store[src/store]
```
### Architecture Rules
Each rule names what enforces it. **checked by `<command>`** — a command the
target repo already has (its own dependency-cruiser, import-linter, linter or a
test); `lib/verification/arch-rules.mjs` runs dependency-cruiser and
import-linter when the repo configures them, and installs nothing. **advisory —
`.claude/rules/<file>.md`** — guidance Claude Code loads in the target repo; a
plan step writes that file. A checked rule is accepted only once it has been
seen to pass, fail on a planted violation, and pass again: the Proof column
names the step that shows it (`arch-rules.mjs --prove --rule <name> --plant
<file>=<dest>` does it in one command for the two supported tools; the planted
run must trip that rule).
| Rule | Enforced by | Proof |
|------|-------------|-------|
| {core never imports cli} | checked by `{node_modules/.bin/depcruise --config .dependency-cruiser.cjs src}` | Step {N} |
| {prefer pure functions in core} | advisory — `.claude/rules/{core}.md` | — |
### Requirements Check
Conflicts and gaps between the brief's requirements, each asked once as a
two-choice question with the recommendation first: **keep** (the requirement as
written) or **change like this** (a concrete proposal). Record the answer here.
An answer that changes the brief's Intent, Goal or Success Criteria stops the
plan: the brief is re-run through `/trekbrief`, never edited by the planner.
| # | Finding | Question | Answer |
|---|---------|----------|--------|
| 1 | {two requirements that cannot both hold / a case no requirement covers} | Keep, or change like this: {proposal}? | {keep / change} |
*If there is nothing to ask, write "No conflicts or gaps found" and say what was compared.*
### Decisions (ADR)
*Optional.* Only for a decision that is hard to reverse, surprising without
context, AND the result of a real trade-off. One paragraph each: context,
decision, alternatives rejected and why.
### Gotchas
*Optional.* Each place two constraints collide, the risky call made there, and
who decided it.

View file

@ -18,13 +18,24 @@ source_findings:
> **Plan quality: {grade}** ({score}/100) — {APPROVE | APPROVE_WITH_NOTES | REVISE | REPLAN}
>
> Generated by trekplan v{version} on {YYYY-MM-DD} — `plan_version: 1.7`
> Generated by trekplan v{version} on {YYYY-MM-DD} — `plan_version: 1.8` · `ceremony: {small | bounded | architectural}`
## Context
Why this change is needed. The problem or need it addresses, what prompted it,
and the intended outcome. Reference the spec file if one was used.
## Global Constraints
The brief's Constraints and Non-Functional Requirements that bind more than one
step, **quoted verbatim** — exact values, never paraphrased. A step that could
break one quotes it again in its `Review focus:`.
- > "{constraint, verbatim from the brief}" — brief § Constraints
<!-- ceremony: architectural (or absent) → insert the design part here, from
templates/design-template.md (## Design). small | bounded → omit it. -->
## Architecture Diagram
```mermaid
@ -57,14 +68,25 @@ their relationships, and the data flow between them.*
## Implementation Plan
Each step targets 1–2 files and one focused change. Steps follow TDD structure
when the project has tests.
Each step targets 1–2 files and one focused change, and is a vertical slice:
a narrow but complete path through every layer it touches, verifiable on its
own. Preparatory refactoring comes first, as its own steps. Every step has
`Test first:` (plan_version 1.8 requires it), and one step runs the thing
end to end (`End-to-end:`).
Optional per-step fields: `Interface in:` (what the step consumes, and which
earlier step or existing code produces it), `Interface out:` (what it produces
for later steps), `Review focus:` (inputs the brief implies but no test
exercises yet, each pinned to a test; and any Global Constraint the step could
break, quoted verbatim). A field that is present is never empty.
### Step 1: {description}
- **Files:** `path/to/file.ts`
- **Changes:** {exactly what to modify — no placeholders, no "update as needed"}
- **Reuses:** {existing function/pattern from codebase, with file path}
- **Interface out:** `{name(args) → result}` — read by Step 2
- **Review focus:** {untested input the brief implies} — pinned by `path/to/test.ts`
- **Test first:**
- File: `path/to/test.ts` *(existing | new)*
- Verifies: {what the test checks}
@ -84,15 +106,17 @@ when the project has tests.
must_contain: []
```
### Step 2: {description}
### Step 2: {description — the "run the thing" step}
- **Files:** `path/to/file.ts`
- **Changes:** {exactly what to modify}
- **Reuses:** {existing function/pattern}
- **Interface in:** `{name(args) → result}` from Step 1
- **Test first:**
- File: `path/to/test.ts` *(existing | new)*
- Verifies: {what the test checks}
- Pattern: `path/to/existing-test.ts`
- **End-to-end:** `{the command that runs the product the way a user does — the app, the CLI, the simulator}` → expected: {what the user sees}
- **Verify:** `{exact command}` → expected: `{output}`
- **On failure:** {revert | retry | skip | escalate} — {specific instructions}
- **Checkpoint:** `git commit -m "{conventional commit message}"`
@ -110,8 +134,10 @@ when the project has tests.
pattern: "expected content marker"
```
*For projects without tests: omit "Test first" and keep "Verify" with a
concrete command (e.g., run the app, check output, curl an endpoint).*
*A project without tests still gets `Test first:` on every step: the first step
adds the test runner (or a script under `tests/`) the later steps use. A plan
without an `End-to-end:` step is invalid at plan_version 1.8 — without it the
result can only be "not verified end to end", never green.*
### Manifest — objective completion predicate
@ -257,3 +283,10 @@ later waves depend on earlier waves completing first.*
| # | Finding | Severity | Resolution |
|---|---------|----------|------------|
| 1 | {what was wrong} | {blocker/major/minor} | {how it was fixed} |
<!-- ## Critic Verdict — do NOT write this section. `lib/validators/plan-gate.mjs
--record` appends it after the first critic round (Phase 9) and replaces it on
each later round: one fenced json block with round, max_rounds, plan_sha256
(the plan minus its review log), verdict BLOCK | REVISE | PASS, and the
deduplicated findings. `plan-gate.mjs <plan>` exits 0 only when the plan
validates, the block matches the current plan, and no BLOCKER is open. -->