wei-wuwei 0.0.0-stage → 0.2.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.
- package/CHANGELOG.md +38 -0
- package/LICENSE +21 -0
- package/README.md +241 -2
- package/agents/_template/agent.md +28 -0
- package/agents/wuwei-audit-composition/agent.md +85 -0
- package/agents/wuwei-audit-contract/agent.md +97 -0
- package/agents/wuwei-audit-coverage/agent.md +93 -0
- package/agents/wuwei-implementer/agent.md +34 -0
- package/agents/wuwei-pre-implementation-doubt/agent.md +158 -0
- package/agents/wuwei-review-claims/agent.md +187 -0
- package/agents/wuwei-review-code/agent.md +219 -0
- package/agents/wuwei-review-defects/agent.md +180 -0
- package/agents/wuwei-review-design/agent.md +177 -0
- package/agents/wuwei-review-drift/agent.md +184 -0
- package/agents/wuwei-review-structure/agent.md +86 -0
- package/agents/wuwei-security-auditor/agent.md +229 -0
- package/bin/wuwei.js +2832 -0
- package/package.json +44 -4
- package/skills/_template/skill.md +34 -0
- package/skills/wuwei-brainstorm/skill.md +69 -0
- package/skills/wuwei-commit-hygiene/skill.md +38 -0
- package/skills/wuwei-debug-root-cause/skill.md +48 -0
- package/skills/wuwei-execute-phase/skill.md +624 -0
- package/skills/wuwei-grill/skill.md +67 -0
- package/skills/wuwei-legible-output/skill.md +27 -0
- package/skills/wuwei-map-codebase/skill.md +171 -0
- package/skills/wuwei-plan-phases/skill.md +326 -0
- package/skills/wuwei-review/references/lens-rules.md +41 -0
- package/skills/wuwei-review/references/prep.md +35 -0
- package/skills/wuwei-review/references/scopes.md +56 -0
- package/skills/wuwei-review/references/stream.md +94 -0
- package/skills/wuwei-review/skill.md +495 -0
- package/skills/wuwei-tdd/skill.md +47 -0
- package/templates/code-review.md +137 -0
- package/templates/pr.md +35 -0
- package/wuwei.config.json +51 -0
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wuwei-execute-phase
|
|
3
|
+
description: >-
|
|
4
|
+
Use to execute a planned phase or continue a stream — the user says
|
|
5
|
+
"continue the stream / 接手 / 繼續做", a stream has a signed acceptance
|
|
6
|
+
contract and an eligible phase (dependencies merged, unclaimed or
|
|
7
|
+
stale-claimed), or a merge just unlocked a dependent phase. Runs the fixed
|
|
8
|
+
pipeline: claim → implement → e2e → three or more rounds of
|
|
9
|
+
simplify/review/fix → PR — one phase, or a range on request.
|
|
10
|
+
version: 0.2.0
|
|
11
|
+
mode: triggered
|
|
12
|
+
model: sonnet
|
|
13
|
+
effort: xhigh
|
|
14
|
+
targets: [claude-code, codex]
|
|
15
|
+
tags: [execution, workflow]
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Execute phase
|
|
19
|
+
|
|
20
|
+
## When to use
|
|
21
|
+
|
|
22
|
+
- A signed stream has an eligible phase and this session should take it.
|
|
23
|
+
- The caller gives a range instead of a phase (`## Run scope`). Nothing
|
|
24
|
+
parses the shorthand — this file defines it, so a mistyped token gets asked
|
|
25
|
+
about.
|
|
26
|
+
- Resuming: `git pull`, read `STATE.md`, continue from recorded state. That
|
|
27
|
+
is the whole takeover mechanism.
|
|
28
|
+
|
|
29
|
+
## When NOT to use
|
|
30
|
+
|
|
31
|
+
- No signed contract → `wuwei-plan-phases` first. An unsigned plan means a
|
|
32
|
+
self-defined finish line.
|
|
33
|
+
- Hotfix outside any stream → `wuwei-debug-root-cause` + `wuwei-tdd` +
|
|
34
|
+
`wuwei-commit-hygiene`.
|
|
35
|
+
|
|
36
|
+
## Invariants
|
|
37
|
+
|
|
38
|
+
Hold everywhere; the steps do not restate them.
|
|
39
|
+
|
|
40
|
+
- **Evidence, not narration.** Nothing is done without its recorded green e2e.
|
|
41
|
+
- **A fresh subagent implements, a fresh subagent reviews.** Inherited
|
|
42
|
+
context is not review. Inline only where no subagents exist (Codex) — a
|
|
43
|
+
fallback, not an equal option.
|
|
44
|
+
- **Anything changing what was signed off stops and escalates.** `manual`
|
|
45
|
+
asks now, `auto` records in the phase file and pauses. No scope or `mode`
|
|
46
|
+
pre-approves it.
|
|
47
|
+
- **Transition only what this session observed.** Work merged after handover
|
|
48
|
+
belongs to the next claim's reconcile, or to the merger.
|
|
49
|
+
- **Graph first, Grep as fallback, always record which.** A reconstructed
|
|
50
|
+
edge never carries the confidence of a queried one.
|
|
51
|
+
|
|
52
|
+
## Base sync
|
|
53
|
+
|
|
54
|
+
Steps 1 and 5 both do this.
|
|
55
|
+
|
|
56
|
+
- Merge the **stream branch named in `## Sign-off`**. Read it there, never
|
|
57
|
+
rebuild it from the phase branch name. Named nowhere → stop and say so;
|
|
58
|
+
planning owes it (its step 8).
|
|
59
|
+
- Compare against the integration branch's **tip**, never the sha beside it.
|
|
60
|
+
Syncing to that succeeds, changes nothing, and reports nothing.
|
|
61
|
+
- Sync the **stream branch**, never one phase branch. It is the shared base,
|
|
62
|
+
so one sync serves every later phase; per-phase syncing gives each its own
|
|
63
|
+
merge of main, and those collide.
|
|
64
|
+
- Let codegraph settle afterwards — its watcher reconciles changed paths, so
|
|
65
|
+
a merge is an incremental sync.
|
|
66
|
+
- **Record the ref synced to.** Every graph answer is only true as of it.
|
|
67
|
+
|
|
68
|
+
Then take every diff with **three dots**. Two dots looks right — non-empty,
|
|
69
|
+
plenty to say — and is about the wrong code:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
git diff <base>...HEAD # correct — this phase only
|
|
73
|
+
git diff <base>..HEAD # wrong — the merged base counts as yours
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**The one two-dot diff in this pipeline is step 5's delta round**
|
|
77
|
+
(`wuwei-review` §6): two shas on this same branch with no base movement
|
|
78
|
+
between them, so there is no merged base there to fold in — and a sync that
|
|
79
|
+
moved the base is exactly what voids the delta and sends that round back to
|
|
80
|
+
full scope.
|
|
81
|
+
|
|
82
|
+
## Run scope
|
|
83
|
+
|
|
84
|
+
Steps 1–8 cover **one** phase. How many times you go round is settled once
|
|
85
|
+
per invocation.
|
|
86
|
+
|
|
87
|
+
- Default: `manual` → one phase. `auto` → the whole stream, **never
|
|
88
|
+
re-asked**, because sign-off authorised it.
|
|
89
|
+
- Shorthand: `--through <NN>` inclusive, `--through end`, `--all`, or the
|
|
90
|
+
same in words.
|
|
91
|
+
- Given a range, print it and go. Given none, ask.
|
|
92
|
+
|
|
93
|
+
Print before claiming anything: the scope line over `wuwei claim
|
|
94
|
+
<stream>`'s list, which already marks `review: human` and anything waiting or
|
|
95
|
+
blocked — `run scope: 02 → 04 · 3 phases · mode: manual`, then where it
|
|
96
|
+
will stop and which phase starts.
|
|
97
|
+
|
|
98
|
+
Stopping early is normal — say where, why, and what resumes:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
stopped at 03-appcheck-wiring · bound e2e red (auth/refresh.spec.ts)
|
|
102
|
+
02 merged. 03 claimed, branch pushed, not merged.
|
|
103
|
+
next invocation resumes at 03: /wuwei-execute-phase
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Name the invocation: this skill's sonnet / xhigh holds for the turn it runs
|
|
107
|
+
in, and a reply in chat continues on the session's model.
|
|
108
|
+
|
|
109
|
+
**Scope is distance, never permission.** `mode` is the stream's standing
|
|
110
|
+
authorisation from sign-off; scope is only how far one invocation tries to
|
|
111
|
+
get.
|
|
112
|
+
|
|
113
|
+
- `review: human` phases were circled at sign-off. The run **always stops**
|
|
114
|
+
at each, and **no token skips it** — carrying through takes words, naming
|
|
115
|
+
the reason it was circled (auth / payments / migrations / irreversible).
|
|
116
|
+
- There is deliberately **no "skip the gates" token**: an endpoint already
|
|
117
|
+
implies not pausing, so a second one adds **no reach at all** — only a name
|
|
118
|
+
that reads as permission to override `mode`.
|
|
119
|
+
- A red bound e2e, a SPEC-changing discovery, a dependency conflict, and
|
|
120
|
+
entering main stop regardless of scope.
|
|
121
|
+
|
|
122
|
+
## Procedure
|
|
123
|
+
|
|
124
|
+
1. **Claim.** Pull; pick a ready phase from `wuwei claim <stream>`, or decide
|
|
125
|
+
a stale claim is abandoned (`--take-over` records it in the phase file).
|
|
126
|
+
|
|
127
|
+
**Catch the stream branch up before cutting anything**: base sync, then
|
|
128
|
+
re-run the stream's already-green e2e on it. Red → `manual` stops and
|
|
129
|
+
reports, `auto` surfaces a stuck stream; **never cut a phase branch off a
|
|
130
|
+
stream branch whose evidence is red**. The sync moves the base under any
|
|
131
|
+
in-flight phase — they sync again at their step 5, so no coordination is
|
|
132
|
+
needed, but note it in the phase file.
|
|
133
|
+
|
|
134
|
+
Then `wuwei claim <stream> <NN>` claims it and cuts `wuwei/<stream>/NN-<name>`
|
|
135
|
+
**from the stream branch** — not main, which would put the whole base
|
|
136
|
+
delta in this phase's PR.
|
|
137
|
+
|
|
138
|
+
**Tracker-linked?** Read each phase's issue from its own `tracker-issue`
|
|
139
|
+
frontmatter, never `STATE.md` — `done/total` is an aggregate and cannot
|
|
140
|
+
say *which* phase merged. Compare this phase and every earlier one against
|
|
141
|
+
the state its phase file implies, then apply the single write rule:
|
|
142
|
+
|
|
143
|
+
> **Only move an issue whose current state is one of the three names
|
|
144
|
+
> recorded at sign-off.**
|
|
145
|
+
|
|
146
|
+
Those three are ordered (in-progress → in-review → done), so "behind" is
|
|
147
|
+
decidable inside the set, and catching an earlier phase up is a write wuwei
|
|
148
|
+
owed. **That is the only write that is yours — forward, to catch up.**
|
|
149
|
+
Never backwards: an issue a human moved to `done` is not reopened because
|
|
150
|
+
a phase file still reads in-review. Anything outside the set — `Blocked`, `Won't Do`, `In QA`, anything
|
|
151
|
+
nobody mapped — is a human acting on the board: report and leave it,
|
|
152
|
+
**including when it is the phase you are claiming**. Under `single`
|
|
153
|
+
granularity there is no per-phase issue — see step 7.
|
|
154
|
+
|
|
155
|
+
2. **Implement** the task checklist, one fresh subagent per task (SDD,
|
|
156
|
+
borrowed from superpowers). **Dispatch with four things:** SPEC, the phase
|
|
157
|
+
context, **the ladder below**, and **step 4's floor** — and nothing else.
|
|
158
|
+
The ladder is a question the subagent writing the helper has to ask; an
|
|
159
|
+
orchestrator holding it while the subagent writes is the same as not having
|
|
160
|
+
it. Dispatch `wuwei-implementer` with **no `model` or `effort` on the
|
|
161
|
+
call** — its file pins sonnet / xhigh, and a value on the call beats it.
|
|
162
|
+
Inline instead → watch for
|
|
163
|
+
drift, keep the phase small, and note that the model policy has nothing to
|
|
164
|
+
attach to.
|
|
165
|
+
|
|
166
|
+
**A task waits for every task in its `depends-on`** (`wuwei-plan-phases`
|
|
167
|
+
sets them) — dispatched only once those have landed. Tasks with no
|
|
168
|
+
`depends-on` are independent and may go in parallel. **A missing field
|
|
169
|
+
means independent, so a mis-planned one runs too early and its subagent
|
|
170
|
+
writes against an interface that is not there yet**; that is a planning
|
|
171
|
+
defect, reported, not worked around here.
|
|
172
|
+
|
|
173
|
+
`wuwei-tdd` governs each task; tick as they land; one task ≈ one commit
|
|
174
|
+
(`wuwei-commit-hygiene`). Library choice and internal structure are yours
|
|
175
|
+
— don't ask.
|
|
176
|
+
|
|
177
|
+
**Each commit stands where it is written.** One-per-task is a floor, not a
|
|
178
|
+
cap: a task holding two real concerns commits twice, in dependency order;
|
|
179
|
+
what is never allowed is one commit holding two.
|
|
180
|
+
|
|
181
|
+
- **No forward dependency.** Building on what an earlier commit landed is
|
|
182
|
+
the `depends-on` sequence working — task 3 using task 2's type is
|
|
183
|
+
correct. Referencing a helper, field, export or migration that a **later**
|
|
184
|
+
commit adds is not: that commit is half a change with a message, and it
|
|
185
|
+
breaks `git bisect` at the exact commit someone reaches for. Needed and
|
|
186
|
+
not there yet → **its task lands first**, never "I'll wire it up after".
|
|
187
|
+
- **The design is readable from the commit alone.** Subject names the
|
|
188
|
+
concern; the body says **why this shape** — and where the choice was not
|
|
189
|
+
obvious, the rung it stopped at and what it climbed past. Someone holding
|
|
190
|
+
only `git show` should not need the phase file to see the intent.
|
|
191
|
+
- The one commit allowed to be red is a `wuwei-tdd` test committed ahead of
|
|
192
|
+
its implementation, and only with that implementation as the **very next**
|
|
193
|
+
commit. Anything committed in between leaves a red commit that reads as a
|
|
194
|
+
broken tree.
|
|
195
|
+
|
|
196
|
+
**Climb before writing**, stopping at the first rung that holds. Skipping a
|
|
197
|
+
rung is not a different kind of mistake from step 4's — it is the same
|
|
198
|
+
finding, arriving later, so the rungs and step 4's tags are one vocabulary:
|
|
199
|
+
|
|
200
|
+
| | Ask | Skipped → step 4 reports |
|
|
201
|
+
|---|---|---|
|
|
202
|
+
| 1 | does this need to exist at all? | `yagni:` / `delete:` |
|
|
203
|
+
| 2 | **is it already in this codebase?** — a helper, type or pattern a few files over | `reuse:` |
|
|
204
|
+
| 3 | does the stdlib do it? | `stdlib:` |
|
|
205
|
+
| 4 | does a native platform feature cover it? | `native:` |
|
|
206
|
+
| 5 | does an **already-installed** dependency? Never add a new one for what a few lines do | `reuse:` |
|
|
207
|
+
| 6 | can it be one line? | `shrink:` |
|
|
208
|
+
| 7 | only then: the minimum code that works | — |
|
|
209
|
+
|
|
210
|
+
Rung 2 is the one that has to be caught here rather than later: `stdlib:`
|
|
211
|
+
and `native:` are visible to anyone reading the diff, while a helper three
|
|
212
|
+
files over is invisible unless you already looked. `review:defects` looks
|
|
213
|
+
too — **both sides gate** — and **a `reuse:` finding from either is a rung
|
|
214
|
+
that was skipped**, so it counts in the round's convergence like any other.
|
|
215
|
+
|
|
216
|
+
**The ladder shortens the solution, never the reading.** Trace every file
|
|
217
|
+
the change touches and the flow it really takes first, then climb — the
|
|
218
|
+
smallest change in the wrong place is not lazy, it is a second bug.
|
|
219
|
+
|
|
220
|
+
**A fix goes at the proven cause, and when the cause is in a shared
|
|
221
|
+
function, one guard there beats one per caller** — smaller diff, and the
|
|
222
|
+
siblings stop being broken too. Find the call sites the way `## Invariants`
|
|
223
|
+
says: graph first, Grep as fallback, record which. This holds wherever a fix
|
|
224
|
+
is written — here, step 6, and `wuwei-debug-root-cause` — and it never
|
|
225
|
+
licenses guarding the shared function *before* the cause is proven, which is
|
|
226
|
+
the guess that hides the real one.
|
|
227
|
+
|
|
228
|
+
3. **e2e.** Run the phase's bound items. Red → `wuwei-debug-root-cause`.
|
|
229
|
+
Never proceed past a red bound item. Then `wuwei verify --phase NN`: a
|
|
230
|
+
page bound here and missing from `.wuwei/verify.json` is added first,
|
|
231
|
+
fixtures from the API's schema; each flag is fixed or answered.
|
|
232
|
+
|
|
233
|
+
4. **Simplify.** **Steps 4–6 are one round, and a phase runs at least three.**
|
|
234
|
+
A round cuts, gets reviewed, fixes what came back, verifies, and closes as
|
|
235
|
+
a single commit — so the phase reads as rounds of work rather than a pile
|
|
236
|
+
of fixes.
|
|
237
|
+
|
|
238
|
+
Reread the whole diff and cut. One line per cut, tagged:
|
|
239
|
+
|
|
240
|
+
| Tag | What it marks |
|
|
241
|
+
|---|---|
|
|
242
|
+
| `delete:` | dead code, unused flexibility, speculative feature — nothing replaces it |
|
|
243
|
+
| `reuse:` | something this project already has — a helper, type or pattern in the repo, or an already-installed dependency. Name the file or the package |
|
|
244
|
+
| `stdlib:` | hand-rolled thing the standard library already ships. Name the function |
|
|
245
|
+
| `native:` | a dependency or code doing what the platform already does. Name the feature |
|
|
246
|
+
| `yagni:` | an abstraction with one implementation, config nobody sets, a layer with one caller |
|
|
247
|
+
| `shrink:` | same logic, fewer lines. Show the shorter form |
|
|
248
|
+
|
|
249
|
+
Format: `<file>:L<line>: <tag> <what>. <replacement>.` End with the only
|
|
250
|
+
number that matters — `net: -<N> lines` — or `nothing to cut` and stop.
|
|
251
|
+
Both go in the phase file.
|
|
252
|
+
|
|
253
|
+
**The cut report is one line per cut — no paragraph justifying it.** Every
|
|
254
|
+
paragraph defending a simplification is complexity smuggled back in as
|
|
255
|
+
prose.
|
|
256
|
+
|
|
257
|
+
This governs the cut report and nothing else. Prose that is **required**
|
|
258
|
+
stays in full: `wuwei:` markers (they explain code that is deliberately not
|
|
259
|
+
there, so they are always longer than it), commit bodies (`why`, not what),
|
|
260
|
+
comments stating an invariant, `## Notes`, digests, walkthroughs, phase
|
|
261
|
+
notes.
|
|
262
|
+
|
|
263
|
+
```
|
|
264
|
+
❌ this validator class might be more complex than it needs to be, and
|
|
265
|
+
it's worth considering whether all these rules are needed yet
|
|
266
|
+
✅ auth/email.ts:L12-38: stdlib: 27-line validator class. "@" in the
|
|
267
|
+
address, 1 line; real validation is the confirmation mail.
|
|
268
|
+
✅ api/repo.py:L88: yagni: AbstractRepository, one implementation. Inline
|
|
269
|
+
it until a second exists.
|
|
270
|
+
✅ jobs/sync.go:L52-71: delete: retry wrapper around an idempotent local
|
|
271
|
+
call. Nothing replaces it.
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
`<replacement>` is required, and for `delete:` "nothing" is the answer. The
|
|
275
|
+
❌ is not too polite, it is **unactionable**: no location, no cut, no
|
|
276
|
+
replacement, and a question where a finding belongs.
|
|
277
|
+
|
|
278
|
+
**Never cut a test to make a number better.** A single smoke test or an
|
|
279
|
+
`assert`-based self-check is the floor, not bloat — cutting coverage cuts
|
|
280
|
+
the phase's only evidence. **Tests are outside this step's reach entirely**;
|
|
281
|
+
`review:defects` owns whether they are the right ones.
|
|
282
|
+
|
|
283
|
+
**Never simplify away** input validation at a trust boundary, error handling
|
|
284
|
+
that prevents data loss, a security measure, **anything this project's own
|
|
285
|
+
linters or checks would flag if it were absent** (a11y rules among them,
|
|
286
|
+
when the project has them configured), or anything the contract explicitly
|
|
287
|
+
asked for. A `yagni:` on "config nobody sets" is exactly how one of these
|
|
288
|
+
leaves.
|
|
289
|
+
|
|
290
|
+
The linter clause is deliberate: wuwei does not carry its own opinion on
|
|
291
|
+
what a project must check for — `review:code` already runs whatever the
|
|
292
|
+
project configured. A category with no configured check and no name in
|
|
293
|
+
`## Sign-off`'s threats is not this step's floor to enforce alone.
|
|
294
|
+
|
|
295
|
+
**Two ways the same size → the one that is correct on edge cases.** Fewer
|
|
296
|
+
lines, never a flimsier algorithm.
|
|
297
|
+
|
|
298
|
+
Skipping is allowed only for trivial diffs, and **the skip is recorded the
|
|
299
|
+
same way** — a step whose output is "simplified" is indistinguishable from
|
|
300
|
+
one that was skipped.
|
|
301
|
+
|
|
302
|
+
**A cut you decide not to make gets a marker where it would have gone**,
|
|
303
|
+
not a line in a document nobody will open:
|
|
304
|
+
|
|
305
|
+
```
|
|
306
|
+
# wuwei: <the ceiling this accepts>, <what should trigger revisiting it>
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
```python
|
|
310
|
+
# wuwei: no retry here — the caller retries the whole batch.
|
|
311
|
+
# add one the first time this is called outside that path.
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Two fields, both required. **A marker with no trigger is the one that
|
|
315
|
+
rots**, and step 8 does not pass with one.
|
|
316
|
+
|
|
317
|
+
**Commit the cuts here, before step 5** — step 5's diff is three-dot, so
|
|
318
|
+
cuts left in the working tree are reviewed by nobody while every lens reads
|
|
319
|
+
code that no longer exists. **The bound e2e does not run here**; it runs at
|
|
320
|
+
the round's close, covering this round's cuts and fixes together.
|
|
321
|
+
|
|
322
|
+
5. **Review panel** — run the panel(s) `wuwei-review` §1 classifies this
|
|
323
|
+
phase's diff into: the code panel always, **and the document panel over any
|
|
324
|
+
prose the phase changed** — a phase that ships an endpoint and its docs has
|
|
325
|
+
both, and §1 calls that normal rather than an edge case. `wuwei-review` owns
|
|
326
|
+
the lenses,
|
|
327
|
+
the tool precedence, the three-dot diff, and the collation rules; this
|
|
328
|
+
step supplies the phase context and decides what happens to the result.
|
|
329
|
+
|
|
330
|
+
**Base sync first.** Every graph question the panel asks is about the tree
|
|
331
|
+
that exists *after* this merges — unsynced, "every call site updated" can
|
|
332
|
+
be true here and false the moment it lands.
|
|
333
|
+
|
|
334
|
+
**Then `wuwei review-prep <base>`** (`wuwei-review` §1) — the dispatcher
|
|
335
|
+
checks and the scan bundle; name the bundle's path in the dispatch — one
|
|
336
|
+
crawl for the whole panel, rebuilt whenever the reviewed sha moves.
|
|
337
|
+
|
|
338
|
+
Then dispatch with five things: the phase file, the path to
|
|
339
|
+
`ACCEPTANCE.md`, the **base ref just synced to**, the **tool facts**
|
|
340
|
+
(`wuwei-review` §1, §5), and **the scope** (`wuwei-review` §6) — plus, for the
|
|
341
|
+
document panel, **the intended reader and the facts this phase
|
|
342
|
+
establishes** (`wuwei-review` §3). Models: as `wuwei claim` printed them
|
|
343
|
+
(`wuwei-review` §2).
|
|
344
|
+
|
|
345
|
+
**Round 1 is full scope; every round after it is delta** — dispatched with
|
|
346
|
+
the sha the previous round's panel was reviewed at, that round's still-open
|
|
347
|
+
and `contested` findings, **its `unread:` scopes**, and the phase's full
|
|
348
|
+
range as something a lens may widen to. The unread scopes have to be passed
|
|
349
|
+
explicitly and **read before the delta**: they are unchanged code by
|
|
350
|
+
definition, so nothing else in a delta round would bring them back. Rounds 2 and 3 otherwise pay four lenses to re-read code four
|
|
351
|
+
lenses already read.
|
|
352
|
+
|
|
353
|
+
**Full scope comes back whenever the delta cannot be trusted**, and
|
|
354
|
+
`wuwei-review` §6 lists when: the sync above actually moved the base, or the
|
|
355
|
+
recorded sha no longer resolves. Both are one command to check and neither
|
|
356
|
+
is a judgement call — **not checking is how a delta silently reviews the
|
|
357
|
+
wrong range.**
|
|
358
|
+
|
|
359
|
+
**The dispatch asks for the same thing every round** — the delta and the
|
|
360
|
+
carried findings. A standing order for fresh probes voids the convergence
|
|
361
|
+
count; widening is chosen once and recorded in the digest header
|
|
362
|
+
(`wuwei-review` §6).
|
|
363
|
+
|
|
364
|
+
**A panel whose delta holds nothing for it is skipped, and the skip is
|
|
365
|
+
recorded** — in the digest header, which already asks for any lens that did
|
|
366
|
+
not run and why; same as step 4, an unrecorded skip is indistinguishable
|
|
367
|
+
from a step that was forgotten. Concretely: on a delta round the document
|
|
368
|
+
panel does not dispatch when the delta contains no prose, **and** the
|
|
369
|
+
previous digest carries no open document findings, **and it declared no
|
|
370
|
+
`unread:` scope** — a blind spot the panel located itself is the last thing
|
|
371
|
+
a skip may swallow. A lens shown nothing can
|
|
372
|
+
find nothing, so nothing is given up — except one seam, named with the
|
|
373
|
+
skip: a code-only fix can falsify prose it never touched, and until the
|
|
374
|
+
stream audit only `review:defects`' prose-inside-code rule watches it.
|
|
375
|
+
Round 1 is untouched by this — it runs full scope, where §1's
|
|
376
|
+
classification already decides which panels exist at all. Inside a phase the panel has two obligations it does not
|
|
377
|
+
have standalone:
|
|
378
|
+
|
|
379
|
+
- **Diff the architecture delta against the phase's `## Intended
|
|
380
|
+
design`** and state the verdict — built as designed, or diverged with
|
|
381
|
+
the reason. Divergence is allowed but never silent; divergence that
|
|
382
|
+
changes what was *signed off* rather than how it was built is an
|
|
383
|
+
escalation, not a footnote.
|
|
384
|
+
- **Reconcile `ACCEPTANCE.md`'s `## Threats`** — no evidence means still
|
|
385
|
+
open.
|
|
386
|
+
|
|
387
|
+
Two dimensions the panel weighs **every round**, because they are what the
|
|
388
|
+
rounds exist for:
|
|
389
|
+
|
|
390
|
+
- **logical necessity** — does this need to exist at all? Not "is it
|
|
391
|
+
correct" but "is it load-bearing". A correct thing nobody needs is next
|
|
392
|
+
round's `yagni:`, not a finding to close.
|
|
393
|
+
- **human readability** — can a person read this without reconstructing
|
|
394
|
+
it? Naming that lies, a function that needs its own diagram to follow,
|
|
395
|
+
an abstraction whose only reader is its author.
|
|
396
|
+
|
|
397
|
+
Append the digest to the phase file — it is what a human reads instead of
|
|
398
|
+
the raw diff. Each round appends its own; the sequence is the convergence
|
|
399
|
+
record step 6 reads.
|
|
400
|
+
|
|
401
|
+
6. **Close the round.** Fix what step 5 found — **verify it first, then fix
|
|
402
|
+
at the cause, not where it was reported.** Every finding carries its own
|
|
403
|
+
recipe (`Fails when`): run it before touching anything — or, for a finding
|
|
404
|
+
with nothing to run (a `reuse:`, a naming claim), check the claimed fact
|
|
405
|
+
against the tree. It fails as described → real, go find the cause. It does
|
|
406
|
+
not → the finding closes as `false-positive`, recorded in the round record
|
|
407
|
+
with **what was run, what was observed, and the premise the closure
|
|
408
|
+
assumed** — evidence, not argument, since
|
|
409
|
+
prose against prose is how appeasement comes back — and it counts as a
|
|
410
|
+
closure in the convergence table below. The next round's panel reads the
|
|
411
|
+
round record and can re-raise; that is the check on closing too eagerly.
|
|
412
|
+
|
|
413
|
+
A real finding is then fixed at the cause: a lens read the diff, so its
|
|
414
|
+
coordinate is where the defect became visible; the cause can sit in a file
|
|
415
|
+
it never opened. Locate it first, and where it is not already proven that
|
|
416
|
+
is `wuwei-debug-root-cause` — the skill is not only for red tests, and a
|
|
417
|
+
finding whose cause is a guess is the same situation.
|
|
418
|
+
|
|
419
|
+
**The finding disappearing is not the test; the cause being gone is.** One
|
|
420
|
+
closed by widening a type, wrapping the call in a `try`, deleting the
|
|
421
|
+
assertion that caught it, or a local linter-disable is hidden, not fixed —
|
|
422
|
+
and the next round's panel reads the suppression as intended code.
|
|
423
|
+
|
|
424
|
+
**When the proven cause is this phase's own earlier work — a task commit,
|
|
425
|
+
or an earlier round — the fix goes into that code**, in this round's fix
|
|
426
|
+
commit (never amended into a task commit; see below). Nothing has merged yet, so
|
|
427
|
+
this is the cheapest it will ever be, while a compensating layer on top is a
|
|
428
|
+
second floor on a foundation the panel just called wrong — usually more
|
|
429
|
+
lines than the change it avoids. Layer on top only when the cause sits
|
|
430
|
+
outside this phase, and say so in the digest. A cause inside what was signed
|
|
431
|
+
off is an escalation (`## Invariants`), not a local workaround.
|
|
432
|
+
|
|
433
|
+
Then **run the bound e2e** — red → `wuwei-debug-root-cause` — and **commit
|
|
434
|
+
the fixes, one per concern.** Step 2's rules govern these exactly as they
|
|
435
|
+
govern task commits: one concern each, no forward dependency, and a body
|
|
436
|
+
saying why this shape. Step 4's cuts are already their own commit.
|
|
437
|
+
**Nothing is squashed at the round, and nothing is amended into a task
|
|
438
|
+
commit** — a phase reads as the sequence that produced it, which is worth
|
|
439
|
+
reading only because every commit in it is atomic.
|
|
440
|
+
|
|
441
|
+
**Close the round with its record, appended to the phase file** next to
|
|
442
|
+
step 5's digest:
|
|
443
|
+
|
|
444
|
+
```
|
|
445
|
+
round <n> · scope: <full | delta from <sha>> · reviewed at <sha>
|
|
446
|
+
|
|
447
|
+
- cut: <what step 4 removed>. net: -<N> lines
|
|
448
|
+
- found: <N> findings — <N> HIGH / <N> MED / <N> LOW
|
|
449
|
+
- fixed: <one line per concern — the cause, where it differs from where
|
|
450
|
+
the finding was reported> · premise: <what the closure assumed>
|
|
451
|
+
- e2e: <bound items> green @ <sha>
|
|
452
|
+
- verify: <pages> @ <sha> · <N> flags, each fixed or answered
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
**The record goes in the phase file, not only in a commit body.** The phase
|
|
456
|
+
file merges whichever way the phase does — and where sign-off chose squash,
|
|
457
|
+
step 7 makes any round commit body unreadable the moment the phase lands.
|
|
458
|
+
|
|
459
|
+
**Findings must converge.** From round 2 on, compare `HIGH + MED` against
|
|
460
|
+
the previous round's digest: strictly fewer, or the round did not converge.
|
|
461
|
+
A new LOW is not non-convergence — a fresh lens turning up something small
|
|
462
|
+
is what it is for.
|
|
463
|
+
|
|
464
|
+
**Under delta scope the count is carried + new**, never only what this
|
|
465
|
+
round's dispatch happened to be shown. A carried HIGH leaves the count when
|
|
466
|
+
**its fix, its recorded falsification, or its supersession was observed**
|
|
467
|
+
(`wuwei-review` §6), not when a
|
|
468
|
+
round that was never shown it stayed quiet — otherwise the number falls because the scope shrank, and every rule
|
|
469
|
+
in this table starts measuring the dispatch instead of the code.
|
|
470
|
+
|
|
471
|
+
| after round | state | do |
|
|
472
|
+
|---|---|---|
|
|
473
|
+
| 1 | **every lens that ran found nothing, any severity** | **exit the loop** — nothing to converge means the diff was trivial, and the panel said so itself rather than being told |
|
|
474
|
+
| 1 or 2 | otherwise | next round |
|
|
475
|
+
| ≥ 3 | no HIGH, no MED | **exit the loop** |
|
|
476
|
+
| ≥ 3 | converging, HIGH or MED still open | next round |
|
|
477
|
+
| ≥ 2 | **`HIGH + MED` did not fall** | **stop and escalate**, recorded in the phase file |
|
|
478
|
+
|
|
479
|
+
The round-1 exit is the only way out before three — **every lens that ran**,
|
|
480
|
+
zero findings, not a size guess about the diff, and a mixed phase runs two
|
|
481
|
+
panels so it needs both clean. A phase author cannot declare its own diff
|
|
482
|
+
trivial; the panel can, because it is the one thing here that is not
|
|
483
|
+
grading its own work.
|
|
484
|
+
|
|
485
|
+
**Non-convergence is information, never something to fix by finding less.**
|
|
486
|
+
A phase that cannot converge is mis-scoped, and grinding another round is
|
|
487
|
+
how a panel learns to report less.
|
|
488
|
+
|
|
489
|
+
**A contested finding is not a failure to converge.** Two lenses reaching
|
|
490
|
+
different severities on the same subject — `review:claims` calling a
|
|
491
|
+
documented pattern HIGH where `audit:security` finds no reachable sink — is
|
|
492
|
+
a disagreement, and rounds cannot settle it: neither lens is wrong within
|
|
493
|
+
its own mandate, so grinding produces the same two rows every time. Mark it
|
|
494
|
+
`contested`, **leave it out of the `HIGH + MED` convergence count**, and
|
|
495
|
+
**escalate it by name** — it is a human's call, and recording it as
|
|
496
|
+
"mis-scoped phase" hides which question is actually open.
|
|
497
|
+
|
|
498
|
+
A finding is `contested` only when **reporters rated the same subject
|
|
499
|
+
differently** — one row whose Sev cell records each (`wuwei-review` §7). One
|
|
500
|
+
lens with a finding nobody disputed is not contested; it is open.
|
|
501
|
+
|
|
502
|
+
On exit from the loop:
|
|
503
|
+
|
|
504
|
+
- **Run the repo's own suite once** — every e2e run so far measured only
|
|
505
|
+
this phase's bound items, so nothing has yet asked whether it broke a
|
|
506
|
+
test that was already there. Use the command the repo already uses
|
|
507
|
+
(`package.json` scripts, `Makefile`, the CI workflow); red →
|
|
508
|
+
`wuwei-debug-root-cause`. **No discoverable command → record "suite not
|
|
509
|
+
run" in the phase file.**
|
|
510
|
+
- **Phase evidence** in the phase file, as the phase's last commit, naming
|
|
511
|
+
the number of rounds and the convergence sequence. Push.
|
|
512
|
+
|
|
513
|
+
**`STATE.md` is not touched from a phase branch** — one global file, one
|
|
514
|
+
row per stream, and `phases done/total` is a single cell two parallel
|
|
515
|
+
phases would conflict on. The aggregate is **derived on the stream branch
|
|
516
|
+
by whoever merges the phase PR**, in its own commit.
|
|
517
|
+
|
|
518
|
+
7. **PR** against the stream branch from `## Sign-off`, **ready, not draft**
|
|
519
|
+
(draft means "still changing" — use it only when opening early to run CI).
|
|
520
|
+
**Say which delivery strategy this phase sits under**, so a reviewer does
|
|
521
|
+
not judge an `mvp-first` intermediate phase as if it were finished.
|
|
522
|
+
|
|
523
|
+
**Phase PRs merge into the stream branch unsquashed by default — a merge
|
|
524
|
+
commit — and the stream PR merges into main unsquashed too.** The phase is
|
|
525
|
+
still the rollback unit: `git revert -m 1 <merge-sha>` takes one back in a
|
|
526
|
+
single command, and the commits that produced it stay readable underneath.
|
|
527
|
+
**Squashing is the human's call at sign-off, never this step's** — it
|
|
528
|
+
trades every atomic commit for one, which is what a repo demanding linear
|
|
529
|
+
history buys with.
|
|
530
|
+
|
|
531
|
+
**Take the merge method from `## Sign-off`, never from what the button
|
|
532
|
+
offers** — sign-off recorded which method this stream uses and what the
|
|
533
|
+
repo allows. Using a fallback is fine; using it silently is not, so name it
|
|
534
|
+
in the PR.
|
|
535
|
+
|
|
536
|
+
**Squash chosen → the squash commit body lists the commit subjects, in
|
|
537
|
+
order**, because those commits go unreachable and `wuwei-tdd` settles "did
|
|
538
|
+
the test exist before the implementation" from history order. Merged
|
|
539
|
+
unsquashed, the history answers that itself and no listing is owed.
|
|
540
|
+
|
|
541
|
+
- `review: auto` + evidence green, in auto mode → merge into the stream
|
|
542
|
+
branch, by the method in `## Sign-off`.
|
|
543
|
+
- `review: human` → hand the digest over and wait. **The wait ends on the
|
|
544
|
+
last review's body, not on `reviewDecision`** — an approve can carry a
|
|
545
|
+
condition ("docs first, then merge"), and reviews live at
|
|
546
|
+
`/pulls/:n/reviews` and `/pulls/:n/comments`, not with the issue
|
|
547
|
+
comments; every review's findings enter the round record like the
|
|
548
|
+
panel's own. **A commit after the approve gets `wuwei-review` §6's
|
|
549
|
+
post-approve scope before the merge — dispatched to a fresh
|
|
550
|
+
`review:defects`**, never run by this session, which wrote the code.
|
|
551
|
+
- Whole stream done → **base sync once more, re-run the full e2e**, then
|
|
552
|
+
**hand over to `wuwei-review`'s stream panel**, then open the stream PR
|
|
553
|
+
to main.
|
|
554
|
+
|
|
555
|
+
**Say the audit is available, every time, including in auto mode.** It is
|
|
556
|
+
the only gate positioned to ask whether the delivery matches the contract
|
|
557
|
+
that authorised it (`wuwei-review` §4, `references/stream.md`, says what each of its lenses sees
|
|
558
|
+
that no phase review can). **A gate nobody knows about is not a gate.**
|
|
559
|
+
|
|
560
|
+
```
|
|
561
|
+
stream pwa-redesign · 5/5 phases merged · e2e green
|
|
562
|
+
|
|
563
|
+
before the PR to main, run the stream audit:
|
|
564
|
+
/wuwei-review --stream # contract · coverage · composed security · composition
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
The stream PR is ready, carries the accumulated digests, the audit, and the
|
|
568
|
+
UAT checklist, **names the ref synced to** (the UAT is evidence about that
|
|
569
|
+
tree and no other), and states whether the composed result still matches
|
|
570
|
+
`## Target architecture`.
|
|
571
|
+
|
|
572
|
+
**Tracker**, subject to step 1's write rule:
|
|
573
|
+
|
|
574
|
+
| granularity | on PR open | on merge |
|
|
575
|
+
|---|---|---|
|
|
576
|
+
| `per-phase` | phase issue → review state | → done state |
|
|
577
|
+
| `single` | tick that phase's box in the stream issue | **never transition the issue** — closing the stream's only ticket because phase 01 of 5 landed is the destructive version of this feature |
|
|
578
|
+
|
|
579
|
+
A `review: human` phase, and the stream PR into main, merge after this
|
|
580
|
+
session hands over — **say at sign-off who owns those final moves**, or the
|
|
581
|
+
board stops one step short with nobody owning it.
|
|
582
|
+
|
|
583
|
+
8. **Verify.** **At least three rounds, or exactly one if it exited on the
|
|
584
|
+
all-zero rule**, each closed by a green bound e2e, and the convergence
|
|
585
|
+
sequence recorded — a round with no digest is a round that did not happen;
|
|
586
|
+
**every `contested` finding named and escalated**, never counted as
|
|
587
|
+
non-convergence; **the repo's suite run once after the last code change, or
|
|
588
|
+
"suite not run" recorded with the reason**;
|
|
589
|
+
**every round's digest records the scope it ran at and the sha it reviewed,
|
|
590
|
+
round 1 ran full, and any panel skipped on an empty delta is recorded with
|
|
591
|
+
its reason**; **every `unread:` scope a digest declared was read by a later
|
|
592
|
+
round or carried into the phase evidence as still unread**; `STATE.md`'s row for this stream matches the phase
|
|
593
|
+
files, updated on the stream branch; **every `wuwei:` marker this phase
|
|
594
|
+
added names both a ceiling and a trigger**; **no commit in this phase
|
|
595
|
+
depends on one that lands after it**; every round's fixes name a
|
|
596
|
+
located cause rather than a suppression; every tracker transition
|
|
597
|
+
attempted recorded with its outcome, failures in the digest — done against
|
|
598
|
+
a board that never moved must not pass; no red branch left behind
|
|
599
|
+
silently.
|
|
600
|
+
|
|
601
|
+
## Notes
|
|
602
|
+
|
|
603
|
+
- Idea credit: superpowers subagent-driven development + the owner's
|
|
604
|
+
pipeline. Step 4's tag vocabulary and net-lines metric: ponytail's
|
|
605
|
+
`ponytail-review`; step 2's ladder and step 4's floor: ponytail's `ponytail`.
|
|
606
|
+
Rewritten for wuwei.
|
|
607
|
+
- The `review: human` asymmetry is the design: the safe thing costs two
|
|
608
|
+
tokens, the risky thing costs a sentence.
|
|
609
|
+
- SDD's value is freshness — each task starts clean instead of inheriting the
|
|
610
|
+
debris of every task before it, which is what makes late tasks in a long
|
|
611
|
+
phase drift.
|
|
612
|
+
- A `wuwei:` marker is the only decision a project keeps that outlives its
|
|
613
|
+
stream: SPEC and phase digests close when the stream does, the reason a
|
|
614
|
+
function has no retry does not.
|
|
615
|
+
- **One command rolls a phase back, and which command is the merge method's
|
|
616
|
+
doing**: `revert -m 1` for a merge commit (the default), plain `revert` for
|
|
617
|
+
a squash, and rebase gives neither. None of them makes a phase
|
|
618
|
+
*independent* — that is cut at planning time (`wuwei-plan-phases` step 4),
|
|
619
|
+
and recorded in `## Sign-off` because the person reverting is holding an
|
|
620
|
+
incident, not reading the plan.
|
|
621
|
+
- Tracker writes are outward-facing and can fail. A failure never blocks the
|
|
622
|
+
phase, but it goes in the digest and step 8 gates on it.
|
|
623
|
+
- Entering main is always a human decision; phase → stream-branch merges ride
|
|
624
|
+
the sign-off authorisation.
|