feat(plan): plan 1.8, the plan gate, the design part and the plan-side checks

Wave 1, order 3 (P3 plan mode as the start, P2 design as its own part, P9
plan side). Contracts K3-K6 for the later merges.

- plan_version 1.8 (1.7 plans stay valid): Test first on every step, one
  End-to-end ("run the thing") step, optional Interface in / Interface out /
  Review focus fields, a ceremony class in the header (absent =
  architectural), and for architectural plans a ## Design part: module map
  without cycles, architecture rules that name their enforcer and the step
  that proves them, a requirements check asked as keep / change.
- K3 lib/validators/plan-gate.mjs: the critic verdict is recorded INSIDE the
  plan (Claude Code's plan approval hands a hook only the plan file's text),
  bound to the hash taken before the reviewers read it; 0 go / 1 stop / 2
  could not run; at most 3 critic rounds, then stop and ask.
- K5 lib/verification/arch-rules.mjs: runs the target repo's own
  dependency-cruiser or import-linter (installs nothing; 2 = not measured,
  never green); --prove --rule shows pass -> fail on a planted violation of
  that rule -> pass. Verified against dependency-cruiser 18.5.0 and
  import-linter 2.15; madge 8.0.0 left out (missed a planted .mjs cycle).
- K6 lib/verification/plan-scope-sweep.mjs: changed files no step names.
- /trekplan Phases 8-10: design part, bounded critic loop, the gate before
  "execute", a plan-mode path through ExitPlanMode (not yet run end to end
  inside plan mode). plan-critic 10 -> 12 dimensions; scope-guardian checks
  the ceremony.
- Fixed on the way: plan-validator and plan-review-dedup used the
  file://argv[1] main guard (no-op under a symlink or a space); CRLF plans
  failed every manifest; the dedup dropped finding severity.

Borrowed, credited in place: obra/superpowers, Kiro (docs), addyosmani/
agent-skills, mattpocock/skills, GitHub Spec Kit, bashebr/ai-native-sdlc,
Boris Cherny's public threads.

Suite 1497 (1495 / 0 / 2), 86 new tests.

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

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. -->