@tianhai/pi-workflow-kit 2.8.0 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,239 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Read-only structural validation of a workflow design document.
4
+ *
5
+ * Structure only: it does not judge whether a criterion is true, testable, or specific.
6
+ *
7
+ * Usage: node validate-design.mjs <design-path>
8
+ */
9
+ import { readFileSync } from "node:fs";
10
+ import { parseArgs } from "node:util";
11
+
12
+ const TAG_VALUES = {
13
+ Checkpoints: ["none", "full"],
14
+ Review: ["skip", "parallel", "inline"],
15
+ "Feature review": ["auto", "parallel", "inline"],
16
+ };
17
+ const HEADING = /^ {0,3}(#{1,6})[ \t]+(.+?)\s*#*\s*$/;
18
+ const REQUIREMENT = /^R([1-9][0-9]*):\s*(.*)$/;
19
+ const REQUIREMENT_LIKE = /^R(?:[0-9]|\s*:)/;
20
+ const CRITERIA = /^\*\*Acceptance criteria\*\*(?:\s*(?:—|–|-|:).*)?$/;
21
+
22
+ /** Blank fenced examples, keeping an unclosed-fence diagnostic. Not a Markdown renderer. */
23
+ function visibleLines(text) {
24
+ const lines = [];
25
+ const errors = [];
26
+ let fence = "";
27
+ let fenceLine = 0;
28
+ // Python's splitlines: break on CRLF, CR, or LF, and never keep a trailing empty line.
29
+ const rawLines = text.split(/\r\n|\r|\n/);
30
+ if (/[\r\n]$/.test(text)) rawLines.pop();
31
+ for (const [offset, line] of rawLines.entries()) {
32
+ const number = offset + 1;
33
+ if (fence) {
34
+ const char = fence[0] === "`" ? "`" : "~";
35
+ if (new RegExp(`^ {0,3}${char}{${fence.length},}[ \\t]*$`).test(line)) fence = "";
36
+ lines.push("");
37
+ continue;
38
+ }
39
+ const opening = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(line);
40
+ if (opening && !(opening[1][0] === "`" && opening[2].includes("`"))) {
41
+ fence = opening[1];
42
+ fenceLine = number;
43
+ lines.push("");
44
+ } else {
45
+ lines.push(line);
46
+ }
47
+ }
48
+ if (fence) errors.push(`line ${fenceLine}: unclosed code fence; close it before validating`);
49
+ return { lines, errors };
50
+ }
51
+
52
+ /** Presence of content, not its quality. */
53
+ function hasContent(lines) {
54
+ return lines.some((line) => {
55
+ const text = line.replace(/^\s*(?:[-+*]|[0-9]+[.)])\s*/, "").trim();
56
+ // Unicode word characters: a criteria section written in CJK is not empty.
57
+ return Boolean(text) && /[\p{L}\p{N}_]/u.test(text);
58
+ });
59
+ }
60
+
61
+ /** A heading or another bold label terminates a criteria section. */
62
+ function criteriaBody(lines, start, end) {
63
+ const result = [];
64
+ for (const line of lines.slice(start, end)) {
65
+ if (HEADING.test(line) || /^\s*\*\*[^*]+\*\*/.test(line)) break;
66
+ result.push(line);
67
+ }
68
+ return result;
69
+ }
70
+
71
+ function validate(text) {
72
+ const { lines, errors } = visibleLines(text);
73
+ const headings = [];
74
+ for (const [index, line] of lines.entries()) {
75
+ const match = HEADING.exec(line);
76
+ if (match) headings.push({ level: match[1].length, title: match[2], index });
77
+ }
78
+ for (const heading of headings) {
79
+ if (REQUIREMENT_LIKE.test(heading.title) && heading.level !== 3) {
80
+ errors.push(`line ${heading.index + 1}: ${heading.title} must use a ### requirement heading`);
81
+ }
82
+ }
83
+ const requirements = headings.filter((h) => h.level === 3 && REQUIREMENT_LIKE.test(h.title));
84
+ const features = headings.filter((h) => h.level === 2 && h.title === "Feature acceptance");
85
+ const summaries = [];
86
+
87
+ if (requirements.length === 0) {
88
+ errors.push("required requirement block missing; add ### R1: <name> with Acceptance criteria");
89
+ }
90
+ const seen = new Set();
91
+ requirements.forEach((heading, position) => {
92
+ const expected = position + 1;
93
+ const match = REQUIREMENT.exec(heading.title);
94
+ if (!match) {
95
+ errors.push(`line ${heading.index + 1}: malformed requirement '${heading.title}'; use ### R${expected}: <name>`);
96
+ return;
97
+ }
98
+ const number = Number(match[1]);
99
+ if (seen.has(number)) errors.push(`line ${heading.index + 1}: duplicate requirement R${number}`);
100
+ else if (number !== expected) {
101
+ errors.push(
102
+ `line ${heading.index + 1}: expected R${expected}, found R${number}; IDs must be sequential in document order`,
103
+ );
104
+ }
105
+ seen.add(number);
106
+ if (!match[2].trim()) errors.push(`line ${heading.index + 1}: R${number} requires a nonempty name`);
107
+ });
108
+
109
+ const introEnd = requirements.length ? requirements[0].index : lines.length;
110
+ const short = lines.slice(0, introEnd).some((line) => /^In short:\s*\S.*$/.test(line));
111
+ const fullFormat = headings.some((h) => h.level === 2 && (h.title === "At a glance" || h.title === "Requirements"));
112
+ const trivial =
113
+ short &&
114
+ !fullFormat &&
115
+ requirements.length === 1 &&
116
+ requirements[0].title.startsWith("R1:") &&
117
+ features.length === 0;
118
+ if (!trivial && features.length === 0) {
119
+ errors.push(
120
+ "## Feature acceptance is required for non-trivial designs; the trivial exception needs an In short: one-liner and a single R1 block without full-format sections",
121
+ );
122
+ }
123
+ if (features.length > 1) errors.push("duplicate ## Feature acceptance section; keep exactly one");
124
+
125
+ const ownedTags = new Set();
126
+ const tags = (start, end, names, owner) => {
127
+ const values = Object.fromEntries(names.map((name) => [name, TAG_VALUES[name][0]]));
128
+ const found = new Set();
129
+ for (const heading of headings) {
130
+ if (heading.index < start || heading.index >= end) continue;
131
+ for (const name of names) {
132
+ if (
133
+ heading.level !== 3 ||
134
+ // Anchored, as Python's re.match is: a title that merely contains a tag word is not a tag.
135
+ !new RegExp(`^${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`).test(heading.title)
136
+ ) {
137
+ continue;
138
+ }
139
+ ownedTags.add(heading.index);
140
+ if (found.has(name)) errors.push(`line ${heading.index + 1}: duplicate ${name} tag in ${owner}`);
141
+ found.add(name);
142
+ let value = heading.title.slice(name.length).trim();
143
+ value = value.startsWith(":") ? value.slice(1).trim() : "";
144
+ if (!TAG_VALUES[name].includes(value)) {
145
+ errors.push(
146
+ `line ${heading.index + 1}: invalid ${name} tag in ${owner}; expected ${TAG_VALUES[name].join(" | ")}`,
147
+ );
148
+ } else {
149
+ values[name] = value;
150
+ }
151
+ }
152
+ }
153
+ return values;
154
+ };
155
+
156
+ for (const heading of requirements) {
157
+ const end =
158
+ headings.find((h) => h.index > heading.index && (h.level <= 2 || requirements.includes(h)))?.index ??
159
+ lines.length;
160
+ const criteriaEnd = headings.find((h) => h.index > heading.index && h.index < end)?.index ?? end;
161
+ const labels = [];
162
+ for (let i = heading.index + 1; i < criteriaEnd; i += 1) if (CRITERIA.test(lines[i].trim())) labels.push(i);
163
+ const owner = heading.title.split(":")[0];
164
+ if (labels.length === 0) {
165
+ errors.push(`line ${heading.index + 1}: ${owner} needs a standalone **Acceptance criteria** section`);
166
+ } else if (labels.length > 1) {
167
+ errors.push(`line ${labels[1] + 1}: ${owner} has duplicate Acceptance criteria sections`);
168
+ } else if (!hasContent(criteriaBody(lines, labels[0] + 1, end))) {
169
+ errors.push(
170
+ `line ${labels[0] + 1}: ${owner} Acceptance criteria is empty; add a criterion before the next section`,
171
+ );
172
+ }
173
+ const values = tags(heading.index + 1, end, ["Checkpoints", "Review"], owner);
174
+ summaries.push(`${owner}: Checkpoints=${values.Checkpoints}, Review=${values.Review}`);
175
+ }
176
+
177
+ for (const heading of features) {
178
+ const end = headings.find((h) => h.index > heading.index && h.level <= 2)?.index ?? lines.length;
179
+ if (!hasContent(criteriaBody(lines, heading.index + 1, end))) {
180
+ errors.push(
181
+ `line ${heading.index + 1}: Feature acceptance is empty; add an end-to-end criterion before its review tag`,
182
+ );
183
+ }
184
+ const values = tags(heading.index + 1, end, ["Feature review"], "Feature acceptance");
185
+ summaries.push(`Feature review=${values["Feature review"]}`);
186
+ }
187
+
188
+ for (const heading of headings) {
189
+ for (const name of Object.keys(TAG_VALUES)) {
190
+ if (
191
+ new RegExp(`^${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`).test(heading.title) &&
192
+ !ownedTags.has(heading.index)
193
+ ) {
194
+ const owner = name === "Feature review" ? "## Feature acceptance" : "a ### R<n>: requirement block";
195
+ errors.push(`line ${heading.index + 1}: ${name} must be a ### tag inside ${owner}`);
196
+ }
197
+ }
198
+ }
199
+ return { errors, summaries };
200
+ }
201
+
202
+ if (process.argv.includes("-h") || process.argv.includes("--help")) {
203
+ console.log(`usage: node validate-design.mjs <design-path>
204
+
205
+ Read-only structural design validation with Node's standard library only. Semantic correctness is not verified.
206
+
207
+ Pass an explicit design path. Absolute paths are used directly; relative paths resolve from the caller's current working directory (cwd), not the installed skill directory.`);
208
+ process.exit(0);
209
+ }
210
+
211
+ const { positionals } = (() => {
212
+ try {
213
+ return parseArgs({ args: process.argv.slice(2), allowPositionals: true });
214
+ } catch (error) {
215
+ console.error(`validate-design.mjs: ${error.message}`);
216
+ process.exit(2);
217
+ }
218
+ })();
219
+ const design = positionals[0];
220
+ if (!design) {
221
+ console.error("usage: node validate-design.mjs <design-path>");
222
+ process.exit(2);
223
+ }
224
+ let text;
225
+ try {
226
+ // A strict decode: reading as utf8 would replace invalid bytes instead of refusing them.
227
+ text = new TextDecoder("utf-8", { fatal: true }).decode(readFileSync(design));
228
+ } catch (error) {
229
+ console.error(`${design}: cannot read UTF-8 design: ${error.message}`);
230
+ process.exit(2);
231
+ }
232
+ const { errors, summaries } = validate(text);
233
+ if (errors.length) {
234
+ for (const error of errors) console.error(`${design}: ${error}`);
235
+ process.exit(1);
236
+ }
237
+ console.log(`${design}: structural checks passed. Semantic correctness is not verified.`);
238
+ for (const summary of summaries) console.log(` ${summary}`);
239
+ process.exit(0);
@@ -7,11 +7,11 @@ description: "Review a completed requirement's code — trace the logic, check s
7
7
 
8
8
  Review the code just implemented — one tagged requirement, or the whole feature at the feature-level review. **Unlocked** — you may edit code to apply smell fixes; flag everything else as a follow-up.
9
9
 
10
- Any command or tool recipe in this skill is an example, not the requirement — when your host grants a better tool for an operation (a sandboxed batch executor, a structured file API), use the better tool and treat the recipe as a fallback; the only exact exceptions are this kit's `scripts/` helpers and plain `git` invocations, whose deterministic output is the point.
10
+ Any command or tool recipe in this skill is an example, not the requirement — when your host grants a better tool for an operation (a sandboxed batch executor — e.g. `codemode` on pi ≥ 1.0.0 — a structured file API), use the better tool and treat the recipe as a fallback; the only exact exceptions are this kit's `scripts/` helpers and plain `git` invocations, whose deterministic output is the point.
11
11
 
12
12
  ## Process
13
13
 
14
- 1. **Identify the scope** — in the feature-gate flow (the default), you review the **whole feature diff** at the feature-level review (`git diff $FEATURE_BASE...HEAD` — the parent of the first Commit-column entry; see the executing skill's packet recipe); all acceptance criteria in the design doc and the `## Feature acceptance` E2E are in scope. When invoked per-requirement (`Review: inline` on a tagged requirement — or inline-completing a missing delegated role when the tag is `parallel`), scope is just that requirement — read its acceptance criteria from the design doc, run `git log --oneline -5` and `git diff` to see what changed for it. Invoked standalone — no invoking skill, no design doc, no packet — review the span the user names (the working-tree diff, or the branch's commits against its parent branch): tracing, smell fixes, and the hazard check run as usual, while spec alignment has no acceptance criteria to key on — say so and judge the diff against its stated intent instead of manufacturing a coverage table. When the invoking skill already assembled a review packet (the feature packet, or the requirement-scoped `<leaf>-review-packet-r<N>.md`), work from the packet — it is the scope of record; re-derive nothing the packet already states.
14
+ 1. **Identify the scope** — in the feature-gate flow (the default) you review the **whole feature diff** at the feature-level review (`git diff $FEATURE_BASE...HEAD`, `$FEATURE_BASE` being the parent of the first Commit-column entry; see the executing skill's packet recipe), with every design-doc acceptance criterion and the `## Feature acceptance` E2E in scope. Invoked per-requirement (`Review: inline` on a tagged requirement, or inline-completing a missing delegated role when the tag is `parallel`), the scope is that requirement alone — read its acceptance criteria from the design doc and use `git log --oneline -5` plus `git diff` to see what changed. Invoked standalone — no invoking skill, no design doc, no packet — review the span the user names (the working-tree diff, or the branch's commits against its parent): tracing, smell fixes, and the hazard check run as usual, while spec alignment has no criteria to key on — say so and judge the diff against its stated intent rather than manufacturing a coverage table. When the invoking skill already assembled a packet (the feature packet, or the requirement-scoped `<leaf>-review-packet-r<N>.md`), work from the packet — it is the scope of record; re-derive nothing it states.
15
15
 
16
16
  2. **🔍 Code tracing** — trace the new or changed code paths end-to-end against the acceptance criteria and the feature E2E (a trivial design doc has no feature E2E — its acceptance criteria alone are the spec). For each path, determine whether data flows correctly from entry to the asserted outcome. Note any branch the tests do not exercise, any dead branch, or any path where the trace breaks.
17
17
 
@@ -23,7 +23,7 @@ Any command or tool recipe in this skill is an example, not the requirement —
23
23
  |----|---------|----------|
24
24
  | 1 | <verdict> | file:line (code), file:line (test) |
25
25
 
26
- Verdict per requirement: `covered | gap | scope-creep` — `covered` = every criterion has covering code and a test; `gap` = a criterion lacks code or a test; `scope-creep` = the code does more than the criteria specify. Findings elaborate on every non-`covered` row; an all-`covered` table needs no elaboration.
26
+ Verdict per requirement: `covered | gap | scope-creep` — `covered` = every criterion has covering code and a test; `gap` = a criterion lacks code or a test; `scope-creep` = the code does more than the criteria specify; findings elaborate on every non-`covered` row, and an all-`covered` table needs no elaboration.
27
27
 
28
28
  4. **🧹 Code smells — fix these directly:** review the changed code and affected files against the requirement and feature scope, then fix what you find.
29
29
  - Shallow modules (interface nearly as complex as implementation)
@@ -49,8 +49,8 @@ Any command or tool recipe in this skill is an example, not the requirement —
49
49
 
50
50
  - **Tracing and spec alignment are the core** — they catch what tests miss: untested branches, missing criteria, scope creep.
51
51
  - **Fix smells in place; flag everything else.** Keep the review scoped — the goal is polish on the requirement that just landed, not a redesign pass.
52
- - **Be proportional** — a one-function change doesn't need the depth of a batch pipeline. When this skill runs as the inline path because the design doc tagged the requirement `Review: inline`, that was a deliberate call at design approval — keep the review focused and don't second-guess the tag.
52
+ - **Be proportional** — a one-function change doesn't need the depth of a batch pipeline; a `Review: inline` tag was a deliberate call at design approval — keep the review focused and don't second-guess it.
53
53
 
54
54
  ## After the review
55
55
 
56
- Return to `/skill:pwk-executing-tasks` — the next requirement, or the ship checkpoint when every requirement is done. Finalizing is proposed from the ship checkpoint, never from here. (The human tagged this requirement at design approval when its `### Review` tag was set — keep the review focused on the tag's scope.)
56
+ Return to `/skill:pwk-executing-tasks` — the next requirement, or the ship checkpoint when every requirement is done. Finalizing is proposed from the ship checkpoint, never from here.
@@ -5,66 +5,75 @@ description: "Implement a design doc via the feature-gate flow: write the featur
5
5
 
6
6
  # Executing Tasks
7
7
 
8
- Implement the design doc found under `docs/plans/` via the **feature-gate flow**. The design doc is the single buildable artifact — its `### R<n>` blocks carry each requirement's acceptance criteria and tags. The criteria define *what*, you decide *how*: structure, signatures, internals are yours.
8
+ Implement the design doc under `docs/plans/` via the **feature-gate flow**; its `### R<n>` blocks carry each requirement's acceptance criteria and tags. The criteria define *what*, you decide *how*.
9
9
 
10
- Any command or tool recipe in this skill is an example, not the requirement — when your host grants a better tool for an operation (a sandboxed batch executor, a structured file API), use the better tool and treat the recipe as a fallback; the only exact exceptions are this kit's `scripts/` helpers and plain `git` invocations, whose deterministic output is the point.
10
+ Any command or tool recipe in this skill is an example, not the requirement — when your host grants a better tool for an operation (a sandboxed batch executor — e.g. `codemode` on pi ≥ 1.0.0 — a structured file API), use the better tool and treat the recipe as a fallback; the only exact exceptions are this kit's `scripts/` helpers and plain `git` invocations, whose deterministic output is the point.
11
11
 
12
- The feature-acceptance E2E test is the primary enforced gate and the primary enforced spec for the feature. The flow is always on: write the E2E first (red), implement the requirements back-to-back, then run the feature review and pause at the **ship checkpoint** — one fully-informed stop where you present the execution summary and the reviewer coverage table, with the full diff on request. Per-requirement checkpoints and reviews are **opt-in** — they fire only for requirements the design doc tags (default off); the feature gate covers everything else. A trivial design doc (no `## Feature acceptance`, per brainstorming's proportionality rule) skips the E2E steps and ships on the full suite; the one whole-feature review still runs at its ship checkpoint, its missing `### Feature review` tag defaulting to `auto`.
12
+ Reference pointers name the section a step needs: run the section helper `scripts/ref.mjs <reference-path>#<anchor>` instead of reading the whole reference file.
13
+
14
+ The feature-acceptance E2E test is the primary enforced gate and the primary enforced spec. The flow is always on: E2E first (red), the requirements back-to-back, then the feature review and the **ship checkpoint**. Per-requirement checkpoints and reviews are **opt-in** — they fire only when the design doc tags them, and the feature gate covers the rest. A trivial design doc (no `## Feature acceptance`) skips the E2E and ships on the full suite.
13
15
 
14
16
  ## Before you start
15
17
 
16
- Resolve local references and scripts from this installed skill directory. If a required resource is missing, report the blocker and stop before the affected action; do not silently skip its instructions.
18
+ Resolve local references and scripts from this skill directory; a missing required resource is a blocker to report, never to skip.
17
19
 
18
20
  1. **Git state** — `git status` + `git log --oneline -5`; note uncommitted changes.
19
- 2. **Find the doc** — first verify the repo root: run `pwd` (or your shell's equivalent) and `git rev-parse --show-toplevel`; mismatch → report both paths and stop; never `cd` (a worktree root counts). Then list `docs/plans` recursively, excluding docs/plans/completed/, for `*-design.md` (topic docs live in `docs/plans/<date>-<topic>/` folders — archived work is not in flight). Use whatever recurses in your harness; one example: `find docs/plans -name '<suffix>' -not -path '*/completed/*'`. If no doc at all, ask the user to run `/skill:pwk-brainstorming` first; if several, ask which. Report one line, e.g. `Found: design "auth" — feature-gate execute (E2E written, implementing 2/5)`. A matching `*-progress.md` means this is a **resume** (see [Resume and progress](#resume-and-progress)). An umbrella part whose prior leaves are not all at `done`: surface their `Feature phase:` lines (matched header-only from each `<leaf>-progress.md`) as advisory context in the pre-flight report — no refusal, no reorder; build order stays advisory.
20
- 3. **Workspace — choose this topic’s branch/worktree.** Before creating, switching, or adopting one, read [Workspace and resume details](references/resume.md#workspace). Reuse this topic’s branch (one umbrella = one branch); a different topic’s branch never hosts these commits. Uncommitted planning docs do not cross a worktree boundary: commit this topic folder on its branch before a new worktree handoff; when adopting an existing checkout with uncommitted docs here, copy the topic folder there, verify it, then remove the source copy. Read the reference's command order before acting. Offer/adopt only after checking existing worktrees; wait for the user's choice.
21
+ 2. **Find the doc** — first verify the repo root: run `pwd` (or your shell's equivalent) and `git rev-parse --show-toplevel`; mismatch → report both paths and stop; never `cd` (a worktree root counts). Then list `docs/plans` recursively, excluding docs/plans/completed/, for `*-design.md` (topic docs live in `docs/plans/<date>-<topic>/` folders — archived work is not in flight). Use whatever recurses in your harness; one example: `find docs/plans -name '<suffix>' -not -path '*/completed/*'`; take each topic’s `Feature phase:` line header-only (`grep -m1 '^Feature phase:' <file>`). With a sandboxed batch executor (e.g. `codemode` on pi ≥ 1.0.0) the listing and every phase extraction are one call, returning only the summary lines (adapt the paths to the verified root when your cwd differs):
21
22
 
22
- ## First run
23
+ ```javascript
24
+ const designs = (await tools.bash({ command: "find docs/plans -name '*-design.md' -not -path '*/completed/*' | sort", timeout: 15 })).output.trim();
25
+ const files = designs ? designs.split('\n') : [];
26
+ const shellq = (s) => "'" + s.replace(/'/g, "'\\''") + "'";
27
+ const heads = await Promise.all(files.map(d =>
28
+ tools.bash({ command: "grep -m1 '^Feature phase:' " + shellq(d.replace('-design.md', '-progress.md')), timeout: 15 }).then(r => r.output.trim() || 'design')));
29
+ return text(files.map((d, i) => d + ' — ' + heads[i]).join('\n') || 'no in-flight topics');
30
+ ```
23
31
 
24
- 1. **Parse the design doc** — read every `### R<n>:` heading and its `### Checkpoints` / `### Review` tags (defaults `none` / `skip`), plus the feature-level `### Feature review` tag in the `## Feature acceptance` section. Requirements run in **listed order** (build order); do not reorder. Read the `## Feature acceptance` section — it is the E2E you gate on first. A trivial design doc (no `## Feature acceptance`) skips steps 5–6 below and goes straight into the implement phase.
25
- 2. **Create the progress file** beside the design at `docs/plans/<date>-<topic>/<leaf>-progress.md`. Before creating it, read [Progress format](references/progress-format.md) for the exact template, header slots, and row vocabulary. Start at `Feature phase: e2e-written` (trivial doc: `implementing (0/N)`); `Setup: pending` when the design has `## Setup`, otherwise `Setup: n/a`.
32
+ No doc → ask for `/skill:pwk-brainstorming`; several → ask which. A matching `*-progress.md` means a **resume** ([Resume and progress](#resume-and-progress)); an umbrella part whose prior leaves are not all `done` shows their `Feature phase:` lines as advisory context.
33
+ 3. **Workspace** — choose this topic’s branch or worktree: read [Workspace and resume details](references/resume.md#workspace) first; it owns the command order including worktree handoffs. Reuse this topic’s branch (one umbrella = one branch); a different topic’s branch never hosts these commits. Offer or adopt only after checking existing worktrees, then wait for the user.
26
34
 
27
- 3. **Setup pre-flight** *(only if the design doc has a `## Setup` section)* — install dependencies, apply migrations, seed data, then run the existing test suite. **⏸ CHECKPOINT: setup** — present results and wait for approval, then set `Setup: done` in the progress-file header so a resume can confirm it rather than assume it.
35
+ ## First run
28
36
 
29
- 4. **Commit the design docs** — `git add docs/plans/<date>-<topic>/ && git commit -m "docs: add design doc"`. The add is scoped to the topic folder so another in-flight topic's uncommitted drafts never ride this commit (docs/lessons.md hygiene: one commit per topic).
30
- 5. **Write the feature-acceptance E2E test (red).** Read the design doc's `## Feature acceptance` section and encode it as a real test file; run it; confirm it **fails** (it must — little or none of the feature exists yet). If it passes immediately, probe why before proceeding: the behavior may already exist, or the test may be asserting too little. If it still passes and the expected behavior looks wrong, **stop and present** rather than implementing against a wrong spec. Iterate it to green as you implement — fixing the implementation is the default, and you **stop and present only when you are genuinely blocked** (nothing you can do makes it pass, or the E2E itself is wrong). That stop is the reserved failure case; it is not the flow's default pause.
31
- 6. **Notice, not a stop — report the E2E and continue.** Post 1–2 plain-language lines stating **what the E2E proves** ("this test proves that …"), plus the E2E test and its failing output, then go straight into the implement phase **without waiting for approval** — the `## Feature acceptance` text was approved during brainstorm, so there is nothing new here for the human to sign off. The notice is the window to object *before* implementation starts: a human who sees the E2E asserting the wrong thing says so, and you revise, re-run, and re-notice. Keep `Feature phase: e2e-written`.
37
+ 1. **Parse the design doc** — read every `### R<n>:` heading with its `### Checkpoints` / `### Review` tags and the feature-level `### Feature review` tag. Requirements run in **listed order**. The `## Feature acceptance` section is the E2E you gate on first; a trivial doc skips steps 5–6.
38
+ 2. **Create the progress file** beside the design at `docs/plans/<date>-<topic>/<leaf>-progress.md`, writing it with `scripts/progress.mjs` (read [Progress format](references/progress-format.md#progress-file) first for the template). Start at `Feature phase: e2e-written` (trivial doc: `implementing (0/N)`); `Setup: pending` when the design has `## Setup`, otherwise `Setup: n/a`.
39
+ 3. **Setup pre-flight** *(only if the design doc has a `## Setup` section)* — install dependencies, apply migrations, seed data, then run the suite. **⏸ CHECKPOINT: setup** — present results and wait for approval, then set `Setup: done`.
40
+ 4. **Commit the design docs** — `git add docs/plans/<date>-<topic>/ && git commit -m "docs: add design doc"`, scoped to the topic folder so another topic’s drafts never ride it.
41
+ 5. **Write the feature-acceptance E2E test (red)** — encode the `## Feature acceptance` section as a real test, run it, confirm it **fails**. If it passes immediately, probe why before proceeding — the behavior may already exist, or the test may be asserting too little — and if the expected behavior looks wrong, **stop and present** rather than implementing against a wrong spec. Iterate to green; fixing the implementation is the default, and you **stop and present only when you are genuinely blocked** (nothing makes it pass, or the E2E itself is wrong).
42
+ 6. **Notice, not a stop — report the E2E and continue.** Post 1–2 plain-language lines stating **what the E2E proves** ("this test proves that …") plus its failing output, then go straight into the implement phase **without waiting for approval** — the `## Feature acceptance` text was approved during brainstorm.
32
43
 
33
44
  ## Resume and progress
34
45
 
35
46
  `Feature phase` is one of: `e2e-written`, `implementing (k/N)`, `reviewing`, `ship-paused`, `done`.
36
47
 
37
- **Done cell:** `⬜` not started · `🔄` in progress · `✅` done · `❌` failed · `⏭` skipped. A row is **terminal** when its Done cell is `✅`, `❌`, or `⏭` — resolved, not necessarily passed. Only executing changes Done cells; a requirement under review stays `🔄` until a clean pass permits `✅`.
48
+ **Done cell:** `⬜` not started · `🔄` in progress · `✅` done · `❌` failed · `⏭` skipped. A row is **terminal** when its Done cell is `✅`, `❌`, or `⏭` — resolved, not necessarily passed. Only executing changes Done cells; a reviewed row stays `🔄` until a clean pass permits `✅`.
38
49
 
39
- When a matching progress file exists, read [Resume](references/resume.md#resume) before routing. Read the header, Requirements table, and Execution summary only; `ship-paused` also needs Code digest. A pending setup checkpoint must be re-verified and approved before proceeding. Resume the first nonterminal row (`⬜`, `🔄`, blank); `✅`/`❌`/`⏭` are terminal, resolved rather than necessarily passed. Match `grep -m1 '^Feature phase:' <file>` for the phase header; `reviewing` resumes review; `ship-paused` re-presents and waits, never approves itself. Missing reviewer reports require review again before showing coverage.
50
+ When a matching progress file exists, read [Resume](references/resume.md#resume), then the header, Requirements table, and Execution summary only (`ship-paused` also needs the Code digest). Resume the first nonterminal row (`⬜`, `🔄`, blank). Match `grep -m1 '^Feature phase:' <file>`; `reviewing` resumes review; `ship-paused` re-presents and waits, never approving itself. Missing reviewer reports require review again before coverage.
40
51
 
41
- Before any progress-row update or code-digest write, read [Progress format](references/progress-format.md). Update the matching row directly, `Last updated`, and `Feature phase`; write execution-summary content at the same time as ✅, and deviations at deviation time. A failed/skipped row carries its reason in the Requirement cell and reconciles its test coverage so the suite stays green.
52
+ Read [Progress format](references/progress-format.md#progress-file) before any progress-row or code-digest write, and drive every structural edit through `scripts/progress.mjs` — it updates the row, `Last updated`, and `Feature phase` together, so write execution-summary content with the ✅ and deviations at deviation time. A failed/skipped row carries its reason and reconciles its test coverage.
42
53
 
43
54
  ## Implement phase
44
55
 
45
- Bugs found mid-execution are mandatory execution-summary content: record the fix in the requirement's `How it was built` cell and fill its Deviated? column at fix time — the summary must show what the feature actually cost to land.
56
+ Bugs found mid-execution are mandatory execution-summary content: record the fix in the requirement’s `How it was built` cell and fill its Deviated? column then.
46
57
 
47
58
  Set `Feature phase: implementing (0/N)` and work the requirements in listed order. For each:
48
59
 
49
- 1. **Mark the requirement 🔄** (Done column), read its `### Checkpoints` / `### Review` tags, and check `docs/lessons.md` for a rule that applies to this slice.
50
- 2. **Write a meaningful test (red), then implement (green)** — TDD discipline. Encode the requirement's acceptance criteria as a real test through the public interface; run it; confirm it fails; implement to green. Skip the per-slice test only when the slice has no independent observable behavior (the feature E2E covers it). Follow the meaningful-test rules: (1) **Test observable behavior** — assert on what the feature produces or changes (a return value, persisted/updated data, an emitted event, an HTTP response) through its public interface; these assertions keep passing as the implementation changes. (2) **Write a per-slice test when the slice has its own observable behavior** — when a slice is pure config or a trivial extraction, the feature E2E covers it and a per-slice test is unnecessary. (Mirrored in `pwk-brainstorming` and `docs/lessons.md`.)
51
- 3. **⏸ per-requirement checkpoint** *(fires only when the tag says so — opt-in)* — if `### Checkpoints: full`, stop and present after the tests and again after the slice is complete — both before its commit (the checkpoint rule below forbids committing before approval). With the default `none`, show the red→green inline and proceed.
52
- 4. **Regression check after each commit** — run the **full existing suite**. This is what catches cross-requirement regressions (a later requirement breaking an earlier one's test). The **feature E2E stays red until the last requirement lands**; you may run it to watch the failure point advance, but it is gated only at the ship checkpoint — never expect it green per-commit.
53
- 5. **Learn.** Caught a repeat mistake? Append a **generic** rule to `docs/lessons.md` (strip domain specifics).
54
- 6. **Commit** the requirement with a clear message; record the requirement's commit hash in the Commit column.
55
- 7. **Per-requirement review** *(fires only when the requirement's `### Review` tag is `parallel` or `inline` — default `skip`)* — review the slice now (see [Per-requirement review](#per-requirement-review-opt-in)); the row stays 🔄 through the review.
56
- 8. **Mark the requirement ✅** and write its execution-summary row in the same step; advance `Feature phase: implementing (k/N)`. For a reviewed requirement this fires only after the review returns clean.
60
+ 1. **Mark the requirement 🔄** (Done column), read its `### Checkpoints` / `### Review` tags, and check `docs/lessons.md` for an applicable rule.
61
+ 2. **Write a meaningful test (red), then implement (green)** — encode the acceptance criteria as a real test through the public interface: red, then green; a slice with no independent observable behavior is covered by the feature E2E. **Test observable behavior** — assert on what the feature produces or changes (a return value, persisted data, an emitted event, an HTTP response) through its public interface.
62
+ 3. **⏸ per-requirement checkpoint** *(fires only when the tag says so)* — with `### Checkpoints: full`, stop and present after the tests and again after the slice is complete, both before its commit; with the default `none`, show the red→green inline and proceed.
63
+ 4. **Regression check after each commit** — run the **full existing suite**, which catches a later requirement breaking an earlier one’s test. The **feature E2E stays red until the last requirement lands**; never expect it green per-commit.
64
+ 5. **Learn.** Caught a repeat mistake? Append a **generic** rule to `docs/lessons.md`.
65
+ 6. **Commit** the requirement; record its commit hash in the Commit column.
66
+ 7. **Per-requirement review** *(only when the `### Review` tag is `parallel` or `inline`)* — review the slice now (see [Per-requirement review](#per-requirement-review-opt-in)); the row stays 🔄.
67
+ 8. **Mark the requirement ✅** and write its execution-summary row in the same step — Evidence cell non-empty, plain words plus pointer; advance `Feature phase: implementing (k/N)`. A reviewed requirement fires only after a clean review.
57
68
 
58
69
  ### Per-requirement review (opt-in)
59
70
 
60
- If the requirement's `### Review` tag is `parallel` or `inline` (default `skip`), review that slice at step 7 — read [Review mechanics](references/review.md) first and use its helper with `--scope requirement --requirement N`, limited to the commits and criteria of that requirement, written to `<design doc's directory>/<leaf>-review-packet-r<N>.md` (requirement-suffixed, so per-requirement packets never overwrite the feature packet or each other). The row stays 🔄 through the review: the four delegated roles — or the one `pwk-code-review` pass on `inline` — report findings, you apply the smell fixes yourself and commit them (the roles are read-only reporters), and a clean pass returns to step 8, which marks the row ✅. With `skip`, no per-requirement review — step 8 fires directly, and the feature-level review covers it.
61
-
62
- With the default `none`, no per-requirement stop fires — the per-requirement test still runs red→green, and the feature review covers implementation quality.
71
+ If the requirement’s `### Review` tag is `parallel` or `inline` (default `skip`), review that slice at step 7: run the [Review mechanics](references/review.md#assemble-evidence) helper with `--scope requirement --requirement N` over that requirement’s commits and criteria, written to `<design doc's directory>/<leaf>-review-packet-r<N>.md`. The four delegated roles — or the one `pwk-code-review` pass on `inline` — only report; you apply the smell fixes and commit them, then a clean pass returns to step 8. With `skip`, no per-requirement review — step 8 fires directly, and the feature-level review covers it.
63
72
 
64
73
  ### Checkpoint gates are mandatory (when the tag says so)
65
74
 
66
75
  When a per-requirement checkpoint fires it is a **hard stop**:
67
- - Stop immediately; never proceed without explicit human approval.
76
+ - Stop immediately; never proceed without explicit approval.
68
77
  - **Never** `git add` or `git commit` before approval at a checkpoint.
69
78
  - Set the progress phase/status **before** pausing.
70
79
 
@@ -72,41 +81,36 @@ When a per-requirement checkpoint fires it is a **hard stop**:
72
81
 
73
82
  When every requirement's Done cell is terminal — `✅` (done), `❌` (failed, reason in row), or `⏭` (skipped, reason in row):
74
83
 
75
- 1. **Run the FULL test suite** — a failure means one requirement regressed another; fix it now, in execute context.
76
- 2. **Run the feature-acceptance E2E** — the test you wrote at the start. It must be **green** now that all requirements have landed. (A `❌`/`⏭` requirement's assertions were reconciled when its row went terminal, so a still-red E2E still means a requirement is missing or wrong.) If it is still red, a requirement is missing or wrong — fix it before proceeding. (A trivial design doc has no `## Feature acceptance` — the full suite staying green is its gate instead.)
77
- 3. **Run the feature review** (below) per the design's `### Feature review` tag — set `Feature phase: reviewing` first, so a mid-review resume routes into this step instead of the implement loop. (A trivial design doc carries no `### Feature review` tag — the missing tag defaults to `auto`, which resolves on its risk content; a trivial diff is typically `inline`, one pass, and there is no E2E to re-green — the full suite is the gate.) The review runs **before** your final approval, so the pause is fully informed. Apply smell fixes yourself and re-green (full suite + E2E) before pausing.
78
- 4. **Write the code digest** into the progress file — the review has succeeded, findings are fixed, and the code is final: read the packet's `## Commits`, `## Changed files`, and `## Diff` sections and fill the progress file's `## Code digest` using [Progress format](references/progress-format.md) and its fill rules. If the packet is stale or missing, read [Review mechanics](references/review.md) and re-run the helper before writing. A resumed `Feature phase: reviewing` that completes lands on this same write point before the checkpoint is assembled. Never a gate: it explains the change, it does not block shipping.
79
-
80
- **Reconcile the Flow against reviewed reality before writing it.** The Flow is written from what was reviewed, not from recollection: in `parallel` mode every hop must correspond to a path the tracing reviewer's report names — no hop invented, no reported path dropped. In `inline` mode there is no separate tracing report — the inline pass itself performs code tracing — so check the Flow against that pass's tracing findings and spec-coverage result instead. A discrepancy you cannot resolve is **surfaced** to the human in the ship checkpoint's findings status, never smoothed over by writing a Flow that omits the path.
84
+ 1. **Run the FULL test suite** — a failure means one requirement regressed another; fix it here. Then run `scripts/stage-check.mjs` and stop on a non-zero exit: the reviewed diff is a commit range, so anything uncommitted outside `docs/plans/` is missing from it.
85
+ 2. **Run the feature-acceptance E2E** — it must be **green** now that all requirements have landed; still red means a requirement is wrong.
86
+ 3. **Run the feature review** (below) per the design’s `### Feature review` tag — set `Feature phase: reviewing` first, so a mid-review resume routes into this step instead of the implement loop. The review runs **before** your final approval, so the pause is fully informed; apply smell fixes and re-green first.
87
+ 4. **Write the code digest** into the progress file — the review has succeeded and the code is final: read the packet’s `## Commits`, `## Changed files`, and `## Diff` sections and fill the file’s `## Code digest` per [Progress format](references/progress-format.md#code-digest); if the packet is stale, re-run the helper first. Never a gate — it explains the change, it does not block shipping. A resumed `Feature phase: reviewing` that completes lands on this same write point. **Reconcile the Flow against reviewed reality**: every hop must match a path the tracing report names — in `inline` mode the inline pass itself performs code tracing, so check the Flow against that pass’s tracing findings and spec-coverage result — no hop invented and none dropped; an unresolvable discrepancy is **surfaced** in the findings status.
81
88
  5. **Set `Feature phase: ship-paused`** and **⏸ CHECKPOINT: ship** — present, in this order:
82
- - a green-gates line: full suite green, feature E2E green (trivial doc: the suite line alone — there is no E2E);
83
- - the **execution summary** — what each requirement became, deviations included;
84
- - the **verdict rows** — list every `❌`/`⏭` row with its reason, so the approval is given knowing what failed;
85
- - the **code digest** — the plain-language change explanation from the progress file (summary, flow, gotchas, key files);
86
- - the **coverage table** (one verdict row per R#) — from the spec-reviewer report in `parallel` mode, from the inline pass's spec alignment in `inline` mode;
89
+ - a green-gates line: full suite green, feature E2E green (trivial doc: the suite line alone);
90
+ - the **execution summary** — what each requirement became, deviations included, Evidence cells quoted;
91
+ - the **verdict rows** — list every `❌`/`⏭` row with its reason, so approval is given knowing what failed;
92
+ - the **code digest** — the plain-language change explanation from the progress file;
93
+ - the **coverage table** (one verdict row per R#) — from the spec-reviewer report in `parallel` mode, from the inline pass’s spec-coverage result otherwise;
87
94
  - findings status: fixed / open for the human;
88
- - "full diff on request" — the raw diff is one command away; show a hunk only where a verdict or finding makes the human ask.
89
-
90
- Wait for approval. **request changes** → fix, re-run the gates (and the review if the change is substantive), re-present.
95
+ - "full diff on request" — show a hunk only where a finding makes the human ask.
91
96
 
92
- A spec-reviewer report without a per-requirement coverage table is invalid — retry the role or complete it inline before pausing; the ship checkpoint is never presented without coverage. (Only the spec role owes the table; the tracing/smell/hazard reports keep their own report shapes.)
97
+ Wait for approval. **request changes** → fix, re-run the gates (and the review if substantive), re-present.
93
98
 
94
- The old "integration gate" is gone — the feature E2E at the ship checkpoint *is* the gate; there is no separate end pass.
99
+ A spec-reviewer report without a per-requirement coverage table is invalid — retry the role or complete it inline before pausing.
95
100
 
96
101
  ## Feature review
97
102
 
98
- This is step 3 of the [ship checkpoint](#ship-checkpoint-all-requirements-terminal--review-merged): it runs **before** the final human approval, so the pause is fully informed. Run **one** review over the **whole feature diff**, driven by the design doc's `### Feature review` tag — exactly one per part, never once per requirement. This is the single thorough review — per-requirement reviews, if any, only saw slices in isolation.
99
-
100
- **Assemble the review packet first** — read [Review mechanics](references/review.md), then invoke the installed skill’s `scripts/build-review-packet.py` with explicit `--project`, `--design`, `--progress`, and `--scope feature`. Check `python3 --version` for Python 3.9+ and helper availability before this step; if Python is missing or unavailable, report the blocker, request a suitable runtime, and stop. Do not auto-install a runtime, use a fallback implementation, or claim packet generation succeeded. No packet byte passes through model output. A failed helper is not usable evidence or approval; correct the inputs, never guess ranges. The helper writes `<leaf>-review-packet.md` beside the design; opt-in packets use `<leaf>-review-packet-r<N>.md`.
103
+ Run **one** review over the **whole feature diff**, driven by the design doc’s `### Feature review` tag — exactly one per part, never once per requirement.
101
104
 
102
- - **Resolve the tag first.** `auto` (the default, and what a missing tag means) resolves on the design's own production-risk content: if the design carries a non-empty `## Production-risk areas` section, or any requirement carries a non-empty `### Production-risk notes`, resolve to `parallel`; otherwise resolve to `inline`. An explicit `parallel` or `inline` is used as written and always wins over `auto` — explicit tag wins in both directions, so a human who wants one pass on a risky design gets one pass.
105
+ **Assemble the review packet first** — run `scripts/stage-check.mjs` and stop on a non-zero exit, then read [Review mechanics](references/review.md#assemble-evidence) and invoke `scripts/build-review-packet.mjs` with explicit `--project`, `--design`, `--progress`, and `--scope feature`. Check `node --version`; if missing, report the blocker, request a suitable runtime, and stop — never auto-install, use a fallback, or claim the packet succeeded. No packet byte passes through model output; a failed helper is never evidence or approval. It writes `<leaf>-review-packet.md` beside the design; opt-in packets use `<leaf>-review-packet-r<N>.md`.
103
106
 
104
- - **`parallel`** — use the host’s `parallel-review` capability for four independent, fresh-context, read-only roles: `pwk-spec-reviewer`, `pwk-tracing-reviewer`, `pwk-smell-reviewer`, `pwk-hazard-reviewer`. Follow [Review mechanics](references/review.md#delegate-or-review-inline): a one-liner packet-file pointer with role framing last; the packet never appears in spawn arguments. Collect one outcome per role. Reviewers only report; you apply smell fixes, commit, and re-green full suite + E2E. Surface trace/spec/hazard findings to the human.
107
+ - **Resolve the tag first.** `auto` (the default, and what a missing tag means) resolves on the design’s production-risk content: a non-empty `## Production-risk areas` section or any `### Production-risk notes` → `parallel`; otherwise `inline`. An explicit tag wins over `auto` in both directions.
108
+ - **`parallel`** — use the host’s `parallel-review` capability for four independent, fresh-context, read-only roles: `pwk-spec-reviewer`, `pwk-tracing-reviewer`, `pwk-smell-reviewer`, `pwk-hazard-reviewer`. Follow [Review mechanics](references/review.md#delegate-or-review-inline): a one-liner packet-file pointer with role framing last — the packet never appears in spawn arguments. Collect one outcome per role. Reviewers only report; you apply smell fixes, commit, and re-green. Surface trace/spec/hazard findings to the human.
105
109
  - **`inline`** — perform `/skill:pwk-code-review` over the whole diff as a single pass.
106
- - **Fallback** — if compatible capability is absent, required read-only/fresh-context/bounded constraints cannot be proved, or delegation fails, do the missing work inline. Retain successful reports; required missing roles mean review is incomplete.
107
- - **Refresh** — if commits land during review, use [Review mechanics](references/review.md) to refresh the packet before any replacement role or digest write. Append requirement-fix IDs before a requirement refresh; keep the initial ID. Packet creation never substitutes for review or approval.
110
+ - **Fallback** — if compatible capability is absent, constraints cannot be proved, or delegation fails, do the missing work inline. Retain successful reports; a missing required role leaves the review incomplete.
111
+ - **Refresh** — if commits land during review, refresh the packet before any replacement role or digest write, appending requirement-fix IDs and keeping the initial ID. Packet creation never substitutes for review or approval.
108
112
 
109
- On success, continue assembling the ship checkpoint; once the human approves it — knowing what failed — set `Feature phase: done`. (An umbrella part's gate is its own progress file; `pwk-finalizing` reads every part's file, and a `❌` in any part blocks the umbrella until the human sends the work back or explicitly types `--force-failed`.)
113
+ On success, continue assembling the ship checkpoint; once the human approves it, set `Feature phase: done`. (An umbrella part’s gate is its own progress file; `pwk-finalizing` reads every part's file, and a `❌` in any part blocks the umbrella until the human types `--force-failed`.)
110
114
 
111
115
  ## Tags reference
112
116
 
@@ -118,7 +122,7 @@ The design doc tags each requirement and the feature level:
118
122
  | `### Review` | `skip \| parallel \| inline` | `skip` | per-requirement review — `parallel` = four delegated reviewers; `inline` = one `pwk-code-review` pass |
119
123
  | `### Feature review` | `auto \| parallel \| inline` | `auto` | the one whole-feature review — always run, never per requirement (a trivial doc carries no tag; the missing tag resolves to `auto`) |
120
124
 
121
- Nothing is tagged silently: **only the human tags** a slice, and the feature review covers everything else. How each tag resolves lives where its decision executes — the [per-requirement review](#per-requirement-review-opt-in) and the [feature review](#feature-review).
125
+ Nothing is tagged silently: **only the human tags** a slice; each tag resolves where its decision executes.
122
126
 
123
127
  ## User override commands
124
128
 
@@ -131,14 +135,14 @@ Nothing is tagged silently: **only the human tags** a slice, and the feature rev
131
135
 
132
136
  ## Receiving feedback (outside a checkpoint)
133
137
 
134
- Verify the criticism against the code, evaluate the suggestion, then implement (with tests) or push back with evidence. Don't blindly apply.
138
+ Verify the criticism against the code, then implement (with tests) or push back with evidence.
135
139
 
136
140
  ## After the feature review
137
141
 
138
- The feature is implemented, reviewed, and approved at the ship checkpoint. Determine the next step from the artifacts (the human drives every transition — this is a suggestion, not a gate; the overview check below is **folder-local** — read the `overview.md` beside this leaf, inside the same `docs/plans/<date>-<topic>/` directory, never a repo-wide `docs/plans/**/overview.md`, and always excluding docs/plans/completed/, so an archived or sibling umbrella never routes):
142
+ Determine the next step from the artifacts — a suggestion, not a gate. The overview check is **folder-local** — the `overview.md` beside this leaf, inside the same `docs/plans/<date>-<topic>/` directory, never a repo-wide `docs/plans/**/overview.md`, and always excluding docs/plans/completed/:
139
143
 
140
144
  - **Standalone topic** (no `overview.md` in the topic folder) → suggest `/skill:pwk-finalizing`.
141
- - **Umbrella part** (an `overview.md` sits beside this leaf) → read the overview's `## Parts (build order)` roster. The umbrella is complete when every roster leaf has a `done` progress file → suggest `/skill:pwk-finalizing` (one PR for the whole umbrella). Otherwise look at the **next leaf** — the **first roster part with no `done` progress file**, not the next entry in build order: build order is advisory, so a part built out of order must not be skipped by the suggestion. That leaf with no progress file and no `<leaf>-design.md` is unstarted → suggest `/skill:pwk-brainstorming` for it; with a `<leaf>-design.md` but no progress file it is designed but never executed → suggest `/skill:pwk-executing-tasks` (its pre-flight picks the design doc up — the same state pwk-status renders as `design`); with a progress file that is not `done` it is mid-flight → suggest `/skill:pwk-executing-tasks` to resume that leaf instead.
145
+ - **Umbrella part** (an `overview.md` sits beside this leaf) → read its `## Parts (build order)` roster; complete when every roster leaf has a `done` progress file → `/skill:pwk-finalizing` (one PR for the whole umbrella). Otherwise the **next leaf** is the first roster part with no `done` progress file — not the next entry in build order: a leaf with no progress file and no `<leaf>-design.md` → `/skill:pwk-brainstorming`; one with a `<leaf>-design.md` but no progress file → `/skill:pwk-executing-tasks`; one whose progress file is not `done` → `/skill:pwk-executing-tasks` to resume it.
142
146
 
143
147
  Present:
144
148
 
@@ -149,7 +153,6 @@ Feature phase: done
149
153
  | # | Done | Requirement |
150
154
  |---|------|-------------|
151
155
  | 1 | ✅ | <name> |
152
- | … | … | … |
153
156
 
154
157
  - Next part: /skill:pwk-brainstorming (unstarted leaf) or /skill:pwk-executing-tasks (designed or mid-flight) — per the routing above ← umbrella, more parts remain
155
158
  - Ship: /skill:pwk-finalizing ← standalone, or last umbrella part
@@ -157,10 +160,10 @@ Feature phase: done
157
160
 
158
161
  ## If you're stuck
159
162
 
160
- 1. Re-read the requirement's acceptance criteria — you may have drifted.
161
- 2. Check `git log` for context. Ask the user — clarify beats guessing.
162
- 3. Still stuck → discard uncommitted changes (`git restore .`); if already committed, also `git revert` the requirement's commit(s). **Never leave a failed requirement's partial work on the shipped branch.**
163
- 4. Set its Done cell `❌` (with the reason as a suffix in the Requirement cell), reconcile its test coverage, and move on. Check `docs/lessons.md` — a prior lesson may apply.
163
+ 1. Re-read the requirement’s acceptance criteria — you may have drifted.
164
+ 2. Check `git log` for context; ask the user — clarify beats guessing.
165
+ 3. Still stuck → discard uncommitted changes (`git restore .`); if already committed, also `git revert` the requirement’s commit(s). **Never leave a failed requirement’s partial work on the shipped branch.**
166
+ 4. Set its Done cell `❌` (with the reason as a suffix in the Requirement cell), reconcile its test coverage, and move on; `docs/lessons.md` may hold an applicable rule.
164
167
 
165
168
  ## Contract index
166
169
 
@@ -189,7 +192,7 @@ Feature phase: e2e-written
189
192
  ## Requirements
190
193
  | # | Done | Requirement | Per-req ceremony | Commit |
191
194
  ## Execution summary
192
- | R# | Requirement | How it was built | Deviated? |
195
+ | R# | Requirement | How it was built | Deviated? | Evidence |
193
196
  ## Code digest
194
197
  ### Summary
195
198
  ### Flow