shapeup-sdlc 3.18.3 → 4.0.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.
Files changed (141) hide show
  1. package/.claude/settings.local.example.json +2 -3
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/AGENTS.md +115 -56
  4. package/README.md +101 -143
  5. package/SECURITY.md +16 -25
  6. package/agents/orient.md +14 -0
  7. package/agents/qa-edge-hunter.md +13 -0
  8. package/agents/spec-evaluator.md +14 -0
  9. package/agents/task-executor.md +14 -0
  10. package/bin/init.mjs +13 -16
  11. package/bin/lib/grant.mjs +8 -19
  12. package/commands/build.md +9 -14
  13. package/commands/eval.md +3 -3
  14. package/commands/hammer.md +9 -5
  15. package/commands/retro.md +12 -11
  16. package/commands/scopes.md +1 -12
  17. package/commands/ship.md +45 -88
  18. package/commands/wire.md +1 -8
  19. package/hooks/dispatch-receipt.mjs +94 -8
  20. package/hooks/hooks.json +0 -41
  21. package/hooks/lib/decision.mjs +6 -9
  22. package/hooks/lib/tier.mjs +50 -0
  23. package/hooks/sandbox-guard.mjs +140 -64
  24. package/kernel/gate.mjs +203 -22
  25. package/kernel/harness.mjs +20 -67
  26. package/kernel/init/run.mjs +175 -523
  27. package/kernel/lib/contract.mjs +9 -93
  28. package/kernel/lib/floor.mjs +64 -0
  29. package/kernel/lib/paths.mjs +39 -112
  30. package/kernel/order.mjs +157 -0
  31. package/kernel/probe/digest.mjs +2 -38
  32. package/kernel/schemas/domain.schema.json +146 -1125
  33. package/kernel/schemas/work-order.schema.json +8 -4
  34. package/kernel/schemas/work-result.schema.json +1 -1
  35. package/kernel/verify/envelope.mjs +2 -2
  36. package/kernel/verify/skills.mjs +27 -8
  37. package/kernel/verify/t0.mjs +2 -2
  38. package/package.json +4 -2
  39. package/skills/building/SKILL.md +144 -0
  40. package/skills/building/resources/gates.md +76 -0
  41. package/skills/building/resources/guidance.md +23 -0
  42. package/skills/{translator/references/preservation-rules.md → building/resources/intake-preservation.md} +1 -1
  43. package/skills/building/resources/intake.md +157 -0
  44. package/skills/building/resources/orders.md +69 -0
  45. package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/doc-schemas.md +1 -1
  46. package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/task-generation.md +13 -13
  47. package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/test-surface.md +6 -7
  48. package/skills/building/resources/plan-scopes.md +95 -0
  49. package/skills/building/resources/plan-spec.md +102 -0
  50. package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/_index.tmpl.md +1 -1
  51. package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/assess-report.tmpl.md +10 -11
  52. package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/run-state.tmpl.md +4 -4
  53. package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/scope-summary.tmpl.md +2 -2
  54. package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/synthesis.tmpl.md +4 -4
  55. package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/usecase.tmpl.md +2 -2
  56. package/skills/building/resources/plan-wire.md +82 -0
  57. package/skills/building/resources/plan.md +98 -0
  58. package/skills/building/resources/retro-research.md +60 -0
  59. package/skills/building/resources/retro-scan.md +49 -0
  60. package/skills/building/resources/retro.md +225 -0
  61. package/skills/building/resources/rounds.md +78 -0
  62. package/skills/building/resources/stop.md +127 -0
  63. package/skills/orient/SKILL.md +37 -37
  64. package/skills/qa-edge-hunter/SKILL.md +14 -14
  65. package/skills/shapeup/SKILL.md +5 -5
  66. package/skills/shapeup/resources/breadboarding.md +1 -1
  67. package/skills/shapeup/resources/context-compaction.md +5 -5
  68. package/skills/shapeup/resources/shaping.md +1 -1
  69. package/skills/spec-evaluator/SKILL.md +17 -21
  70. package/skills/spec-evaluator/references/dimension-contract.md +1 -1
  71. package/skills/spec-evaluator/references/dimensions/completeness.md +3 -3
  72. package/skills/spec-evaluator/references/dimensions/spec-conformance.md +1 -1
  73. package/skills/spec-evaluator/references/dimensions/test-surface-conformance.md +5 -5
  74. package/skills/task-executor/SKILL.md +11 -15
  75. package/commands/hill.md +0 -10
  76. package/hooks/gate-intake.mjs +0 -109
  77. package/hooks/gate-zerowork.mjs +0 -349
  78. package/hooks/tier-guard.mjs +0 -162
  79. package/kernel/compile.mjs +0 -1419
  80. package/kernel/init/fit.mjs +0 -199
  81. package/kernel/init/run-args.mjs +0 -206
  82. package/kernel/lib/breadboard.mjs +0 -165
  83. package/kernel/probe/attempts.mjs +0 -161
  84. package/kernel/probe/concurrency.mjs +0 -535
  85. package/kernel/probe/eval.mjs +0 -405
  86. package/kernel/probe/hunt.mjs +0 -104
  87. package/kernel/probe/leg.mjs +0 -229
  88. package/kernel/probe/owner.mjs +0 -142
  89. package/kernel/probe/requirements.mjs +0 -328
  90. package/kernel/probe/resume.mjs +0 -1110
  91. package/kernel/probe/rounds.mjs +0 -115
  92. package/kernel/probe/staged.mjs +0 -83
  93. package/kernel/probe/stats.mjs +0 -477
  94. package/kernel/probe/t0.mjs +0 -115
  95. package/kernel/reduce/board.mjs +0 -350
  96. package/kernel/reduce/graph.mjs +0 -482
  97. package/kernel/reduce/hill.mjs +0 -322
  98. package/kernel/reduce/ingest.mjs +0 -767
  99. package/kernel/reduce/leftovers.mjs +0 -159
  100. package/kernel/reduce/ship.mjs +0 -529
  101. package/kernel/reduce/snapshot.mjs +0 -291
  102. package/kernel/reduce/verdict.mjs +0 -172
  103. package/kernel/report/export.mjs +0 -384
  104. package/kernel/report/facts.mjs +0 -234
  105. package/kernel/verify/budget.mjs +0 -153
  106. package/kernel/verify/build.mjs +0 -428
  107. package/kernel/verify/dispatch.mjs +0 -114
  108. package/kernel/verify/spec.mjs +0 -975
  109. package/kernel/verify/trace.mjs +0 -604
  110. package/skills/ba-pitch-analyzer/SKILL.md +0 -204
  111. package/skills/coach/SKILL.md +0 -397
  112. package/skills/hill-chart/SKILL.md +0 -154
  113. package/skills/hill-chart/assets/dashboard.template.html +0 -1432
  114. package/skills/scope-architect/SKILL.md +0 -174
  115. package/skills/scope-hammer/SKILL.md +0 -231
  116. package/skills/solution-architect/SKILL.md +0 -158
  117. package/skills/tech-lead/SKILL.md +0 -151
  118. package/skills/tech-lead/references/gates.md +0 -605
  119. package/skills/tech-lead/references/protocol.md +0 -889
  120. package/skills/tech-lead/references/tiny-lane.md +0 -53
  121. package/skills/tech-lead/workflows/shapeup-run.js +0 -2187
  122. package/skills/translator/SKILL.md +0 -258
  123. /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/contract-patterns.md +0 -0
  124. /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/ddd-patterns.md +0 -0
  125. /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/integration-analysis.md +0 -0
  126. /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/ux-behavior-patterns.md +0 -0
  127. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/api-feasibility.tmpl.md +0 -0
  128. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/contracts/be-service.contract.tmpl.md +0 -0
  129. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/contracts/offline-storage.contract.tmpl.md +0 -0
  130. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/contracts/third-party-api.contract.tmpl.md +0 -0
  131. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/context-map.tmpl.md +0 -0
  132. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/event-choreography.tmpl.md +0 -0
  133. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/migration-plan.tmpl.md +0 -0
  134. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/team-handoff.tmpl.md +0 -0
  135. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/domain-model.tmpl.md +0 -0
  136. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/feedback.tmpl.md +0 -0
  137. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/integration.tmpl.md +0 -0
  138. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/task-board.tmpl.md +0 -0
  139. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/task-spike.tmpl.md +0 -0
  140. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/task.tmpl.md +0 -0
  141. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/ux-behavior.tmpl.md +0 -0
@@ -1,889 +0,0 @@
1
- # Protocol — the round loop, the delegation shape, and the invariants behind both
2
-
3
- Three things that only make sense together: what a round DOES, how each step is dispatched, and
4
- which rules the code enforces so a model does not have to remember them.
5
-
6
- On a spec with committed scope contracts all of this is CODE —
7
- `skills/tech-lead/workflows/shapeup-run.js`. This file is the readable rationale for why that code
8
- is shaped the way it is, plus the verbatim prose path for the lanes the script does not cover
9
- (`--tiny`, and any spec with no `scopes/*.md` yet).
10
-
11
- ---
12
-
13
- # Part 1 — The round loop
14
-
15
- The orchestration loop in detail. A "round" is one BUILD phase followed by exactly one
16
- EVAL phase. The feature is done when an EVAL round returns PASS.
17
-
18
- > `tasks/_index.md` referenced throughout this file lives in the LOCAL gitignored root
19
- > (`.shapeup/<slug>/tasks/`, v3.2), not the
20
- > SHARED spec dir. See tech-lead SKILL.md GATE L1b for the bootstrap step that regenerates it
21
- > when missing.
22
-
23
- **On a spec with committed scope contracts, this loop is now CODE, not prose** —
24
- `skills/tech-lead/workflows/shapeup-run.js`'s own `while (round <= args.budgets.maxRounds)` loop
25
- implements exactly the shape below (PASS → ship; `max_rounds` exceeded → GATE H `breaker: outer`;
26
- else the next round builds bugs only), with the EVAL-timing rule, the regression rule, and the
27
- three-level breaker all enforced as branches in that script rather than described here for a model
28
- to follow. Read that script's own comments for the mechanics; this file keeps the historical
29
- rationale and the parts of the protocol the script does not cover (ESCALATE adjudication,
30
- discovered-task reconciliation mid-BUILD — see its banner
31
- for the full list) — and, unchanged, the loop below for a `--tiny` run or a spec with no scope
32
- contracts, which `shapeup-run.js` is out of scope for by design.
33
-
34
- ```
35
- round r = 1
36
- loop:
37
- BUILD(r) # see r=1 vs r>1 below
38
- assert board 100% done # GATE L2 — advisory: the hook warns, you decide
39
- verdict, bugs = EVAL(r) # ONE spec-evaluator --feature pass
40
- if verdict == PASS:
41
- SHIP; break
42
- if r >= max_rounds:
43
- ESCALATE(bugs); break # honest stop — no infinite loop
44
- r = r + 1 # next round builds bugs only
45
- ```
46
-
47
- ## BUILD(r) semantics
48
-
49
- | | r = 1 (initial build) | r > 1 (fix build) |
50
- |--|----------------------|-------------------|
51
- | Input | the whole task board | the bug list from EVAL(r-1) |
52
- | Scope | every ready task, dependency/layer order, until board all ✅ | only the tasks/areas named by bugs |
53
- | Command | compile-order `--next` → task-executor `--order` → ingest, looped | compile-order `--task <id> --operation fix` → dispatch → ingest, per bug |
54
- | Passing areas | n/a | never touched |
55
- | SPIKEs | resolved first (they block) | only if a bug is a SPIKE finding |
56
-
57
- Re-opening tasks in r>1: the fix order's WorkResult reports the task `partial` while failing
58
- and `done` when re-verified; ingest-result flips the board accordingly. The board reflects the
59
- churn so the next EVAL sees a green board again.
60
-
61
- Discovered Tasks:
62
- If WorkResults carry `discoveries[]` during BUILD, ingest-result appends them to the discovery
63
- ledger (`.shapeup/<slug>/discovery/ledger.md`) and the build loop pauses after the current
64
- tasks are done. Compile + dispatch a reconcile order (ba-pitch-analyzer, operation: reconcile).
65
- This reconciles them into new tasks and invariants and updates the board; the tech lead bumps
66
- `discovered_rounds` in harness-run.md, then routes back to GATE L1b (Board Review) for PO
67
- approval of the new tasks and estimates before resuming the BUILD loop.
68
-
69
- ## The EVAL timing rule (the core constraint)
70
-
71
- EVAL fires **once** per round and **only** when GATE L2 has confirmed the board is 100% done
72
- and the round build gate (§3d) is not red — a feature that does not build or launch has nothing
73
- for a judge to grade, and the gate's failing step is what round r+1 fixes.
74
- It is never:
75
- - called per task,
76
- - called inside the BUILD loop,
77
- - called on a partial board.
78
-
79
- ## Regression rule (r > 1) — QA-meeting Bước 1c
80
-
81
- A fix round changes code; a fix can break what passed. Therefore EVAL(r>1) scope is **not**
82
- just the fixed bugs:
83
-
84
- ```
85
- EVAL(r) for r > 1:
86
- touched_UCs = every UC referenced (use_case_refs) by a task re-opened in BUILD(r)
87
- scope = fixed bugs' criteria
88
- + FULL re-run of `## Test Surface` rows for every touched UC
89
- (test-surface-conformance dimension, when active)
90
- + completeness re-check (cheap, static)
91
- untouched UCs' surfaces: NOT re-run (their code didn't change; re-probing everything
92
- every round would turn cheap end-of-round QA into a full-suite tax)
93
- ```
94
-
95
- Pre-v2.9 specs (no Test Surface anywhere): the rule degrades to bug-criteria-only, as
96
- before — and the verdict report notes `regression coverage: none (no test surface)`.
97
- Honest reporting over silent coverage claims.
98
-
99
- ## QA edge hunt (post-PASS, pre-ship)
100
-
101
- When EVAL(r) returns PASS for the **first** time in a run, the orchestrator delegates one
102
- `/qa-edge-hunter` pass before SHIP (skippable via `--no-qa`, same spirit as `--no-eval`).
103
- QA is a pure worker: no verdict, no score, no gate — it writes `~` findings to
104
- `discovery/ledger.md` and a `qa/hunt-report.md`. Triage happens at SHIP/GATE L4:
105
- - all findings stay `~` → SHIP; findings carry over as raw ideas (debt-free).
106
- - PO/TL promote any to must-have → a fix round r+1 (those items only) → EVAL
107
- never a second full hunt) → back to L4.
108
- - Circuit breaker applies: out of rounds/appetite → ship with `~` findings recorded.
109
- QA never runs on a FAIL round — a build that hasn't passed conformance isn't worth
110
- edge-hunting yet.
111
-
112
- Rationale (from the long-running harness work): a single end-of-round QA pass over the
113
- running feature is cheap relative to the build (minutes vs hours) and catches the
114
- last-mile defects, whereas grading every task multiplies evaluator cost for little gain
115
- once the generator is competent. If the build round didn't finish, there is nothing
116
- coherent to evaluate yet.
117
-
118
- ## Stop conditions
119
- 1. **PASS** — EVAL(r) verdict is PASS → SHIP.
120
- 2. **max_rounds (OUTER breaker)** — r would exceed `--max-rounds` (default 3) without PASS →
121
- ESCALATE: print the residual bug list, the rounds used, and hand the decision to the PO
122
- (scope contracts present: also `/scope-hammer --breaker outer`). Do not start another
123
- build round automatically.
124
- 3. **attempt_budget (INNER breaker, scope contracts only)** — a single scope's T0 attempt
125
- loop exhausts `--attempts` (default 5) without reaching a trial that is both `kept` and
126
- T0-green, **or** `no_progress_k` consecutive trials come back non-`kept` (the stagnation
127
- term, default 2 — `harness compile` prints it as a JSON breaker object on stderr) →
128
- does NOT stop the round; queues a hammer PROPOSAL for GATE H and moves to the next scope
129
- in sequence. See "Three-level circuit breaker" below.
130
- 4. **wall_clock_budget (DEADLINE breaker, opt-in)** — elapsed seconds since the run receipt
131
- exceed `--wall-clock-budget` → do NOT start another build round or another scope; go
132
- straight to GATE H (`/scope-hammer --breaker deadline`). Checked with
133
- `harness verify budget` at every round boundary and enforced by `harness verify budget`,
134
- which denies a `task-executor` dispatch past the deadline while leaving `spec-evaluator`,
135
- `scope-hammer` and `qa-edge-hunter` reachable — a run past its deadline
136
- must still be able to judge, hammer, and close. Off unless configured.
137
- 5. **Hard error** — a sub-skill fails irrecoverably (e.g. spec folder gone, app won't
138
- build at all) → stop and report; do not retry blindly.
139
- 6. **User halt** — at any L-gate the user can stop the run; the ledger preserves state for
140
- `--from` resume.
141
-
142
- ## Three-level circuit breaker
143
-
144
- ```
145
- OUTER round_budget (max_rounds) — the six-week-timebox analog. Decremented once per
146
- round at GATE L2, regardless of how many scopes it
147
- covered. Hitting 0 → GATE H immediately (§ above).
148
- INNER attempt_budget (per scope) — decremented once per T0 attempt inside BUILD round r.
149
- Hitting its cap WITHOUT a T0-green result trips the
150
- inner breaker for that scope only: the scope is queued
151
- as a hammer PROPOSAL (not a hard stop) and the round
152
- moves on to the next scope in the L1b sequence.
153
- no_progress_k (default 2) is COMPOSED INTO this same
154
- breaker rather than added beside it as a fourth budget:
155
- attempt_budget counts attempts and cannot see that the
156
- last two produced nothing, so k consecutive non-`kept`
157
- trials queue the same GATE H proposal early.
158
- DEADLINE wall_clock_budget_s — elapsed seconds since the run receipt. Opt-in; off
159
- unless set at L0. Tripping routes to GATE H with
160
- --breaker deadline. Enforced by `harness verify budget`.
161
- ```
162
-
163
- **Why the third one exists — and it corrects an earlier diagnosis.** A run killed at an external
164
- time cap looks like a stall from outside: no verdict, nothing to show. The natural reading is that
165
- it hung at a gate. Often the transcript says otherwise — steady turns, steady writes, gate markers
166
- advancing, zero stall signals. The run was working when the clock ran out.
167
-
168
- Both existing breakers count *events*, not time: `round_budget` moves once per round,
169
- `attempt_budget` once per T0 attempt. Neither can observe that round 1 has been running for
170
- twenty-nine minutes, so a run can burn its entire wall clock with both breakers untouched. The
171
- cost is not the missing verdict — it is that a run killed from *outside* ships nothing, not even the
172
- scopes that were already green. A breaker that trips from the inside routes to GATE H, where
173
- scope-hammer compares the shippable subset against the baseline and ships what works. Same clock,
174
- different ending.
175
- Nesting rationale: a struggling scope should not freeze every other scope's progress
176
- in the same round — only running out of *rounds* (the real six-week analog) stops the whole
177
- run. A scope that trips its inner breaker still gets judged fairly at GATE H: scope-hammer
178
- compares "ship without this scope" against the baseline, same as any other cut candidate — it
179
- is never silently dropped, and it is never allowed to block scopes that ARE working.
180
-
181
- ## Isolated attempt loop — one T0 attempt, in detail (scope contracts only)
182
-
183
- **This is `shapeup-run.js`'s inner per-scope loop, as code**, with one addition the prose below
184
- never had: before opening a scope's attempt loop, the script checks whether THIS round already
185
- has a green T0 verdict for that scope on disk, and skips it when it does — the resumability a
186
- mid-BUILD kill needs, that a session narrating this loop from memory could never guarantee.
187
-
188
- Whichever runs it, the loop is a **ratchet**: every attempt is scored against the last kept one,
189
- and the working tree moves forward only when the score strictly improves. `harness verify t0` makes
190
- that decision and acts on the tree itself, inside the runtime — its caller reads the decision, it
191
- never makes it.
192
-
193
- ```
194
- compile-order --scope … --round N --attempt M
195
- → zero-memory WorkOrder (scope contract + this scope's
196
- tasks + digested errors + ledger decisions +
197
- trial_history: the last 8 trials for this scope, each
198
- with score, status, delta and top-3 digest, CROSSING the
199
- round boundary — compiled facts, no chat history by
200
- construction)
201
- dispatch task-executor --order … → code within substrate; WorkResult in results/
202
- ingest-result <result> → board/ledger writes
203
- (a worker cannot escalate) → WorkResult carries no escalates field. A phase that
204
- cannot finish leaves no artifact, the post-condition
205
- fails, and the run ABORTS naming the phase. Resolve it
206
- yourself and record the answer in round-ledger.md, which
207
- the NEXT attempt's fresh context reads back.
208
- harness verify t0 → fixtures + DB probe, then scores the
209
- attempt against the baseline trial and snapshots or
210
- restores the tree. Branch on `status` from its stdout
211
- JSON — the tree action has ALREADY happened:
212
- kept strictly better, INCLUDING red-but-improved (2/5 → 4/5 fixtures — the whole point
213
- of the ratchet). Tree snapshotted to refs/shapeup/<scope_id>/kept.
214
- overall=green → the attempt loop breaks; scope reaches DOWNHILL_EXECUTION.
215
- Still red → loop, and attempt M+1 now builds ON attempt M.
216
- reverted not better. A tie on a RED score is not better either — but a tie on a GREEN one
217
- KEEPS, because a spec-conformance fix cannot raise a score that is already at
218
- full marks, and reverting it would discard exactly the work a fix round exists
219
- to do. Tree already restored from the last kept
220
- snapshot. Subsumes the retired stash-and-retry branch: an attempt that scores
221
- worse than the incumbent reverts through this same rule.
222
- rather than the code. Tree kept, baseline reset. Not a verdict, not a failure.
223
- crash a fixture command failed to spawn or timed out; tree restored. Fix the fixture,
224
- not the code.
225
- (on any red, `discovered_tasks` carries the AEGIS {file, line, core_message} triples, which
226
- compile-order folds into the NEXT attempt's order as digested_errors — no separate dispatch)
227
- ```
228
-
229
- **The exit code is not the branch selector.** `harness verify t0` exits 0 on T0-green and 1 on
230
- T0-red (2 on bad argv), mirroring the `oracles/*` convention — so a `kept` red-but-improved
231
- attempt, the exact case the ratchet exists for, exits 1. Branch on `status` from the stdout
232
- JSON; never on `$?`, and never wire this call into a `set -e` / `&&` chain that would read a
233
- non-zero exit as "stop".
234
-
235
- This replaces the old flat per-task loop for any scope that has a contract;
236
- scopes/specs without one keep the v0.2.6 behavior verbatim (see BUILD(r) table above).
237
-
238
- ## --no-eval (skip evaluation)
239
- A tech-lead judgment, surfaced at GATE L2: if the feature is clearly within what the model
240
- builds reliably solo, the evaluator is optional overhead. With `--no-eval`, after GATE L2
241
- the run goes straight to SHIP with verdict `not-evaluated` recorded in the ledger and a
242
- clear note that nothing was verified beyond task-executor's own per-AC evidence checks.
243
-
244
- ## Round-cost intuition
245
- Build dominates; eval is cheap. Expect each EVAL round to cost a small fraction of a BUILD
246
- round. This is why running eval once per round (not per task) is the right trade: you pay a
247
- little QA at the end of each build and keep the expensive build coherent in between.
248
-
249
- <!-- test requirement -->
250
- kept|reverted|rebased|crash, decided in harness verify t0 decideStatus()
251
-
252
- ---
253
-
254
- # Part 2 — Delegation
255
-
256
- The tech lead invokes the build-phase skills and reads their handoff files. It never
257
- reimplements their logic. Each sub-skill keeps its own gates; pass `--auto` to a sub-skill
258
- only when the run's auto level is `--auto` or `--unattended`.
259
-
260
- ## Invocation mechanism — Agent, not Skill
261
-
262
- Every "Invoke:" line below means: call the **Agent** tool — a real subagent, on its own
263
- context and (where a role is named) its own model — whose prompt tells it to run
264
- `Skill(shapeup-sdlc-plugin:<name>)` with the given args and report back the artifacts. It does
265
- **not** mean the tech lead calls the `Skill` tool itself. A direct `Skill` call executes
266
- inline, in the tech lead's own turn, on the tech lead's own model — that silently drops GATE
267
- L0.8's model matrix (there is no per-role model left to route once the call is inline) and
268
- breaks the isolation the zero-memory-handoff design (`protocol.md`, the compiled
269
- WorkOrder in `orders/r<N>-a<M>.json`) already assumes every worker below has.
270
-
271
- Standard shape (pure-skill architecture v1.0 — the envelope port):
272
- ```
273
- 1. node "${CLAUDE_PLUGIN_ROOT}/kernel/harness.mjs" compile <mode flags> # → orders/<id>.json
274
- 2. Agent({
275
- description: "<short task description>",
276
- subagent_type: "general-purpose",
277
- model: "<role model resolved at GATE L0.8>",
278
- prompt: "Call Skill(shapeup-sdlc-plugin:<skill>) --order <orders/<id>.json>.
279
- Report back: the WorkResult path (.shapeup/<slug>/results/<id>.json)."
280
- })
281
- 3. node "${CLAUDE_PLUGIN_ROOT}/kernel/harness.mjs" reduce ingest .shapeup/<slug>/results/<id>.json
282
- ```
283
- The WorkOrder carries everything the worker may rely on (payload, decisions, digested errors,
284
- substrate write-contract); the WorkResult carries everything the worker used to write into
285
- shared files. `harness verify envelope` runs as a PreToolUse hook on Skill|Agent and DENIES a
286
- dispatch whose `--order` file is missing or schema-invalid. Workers write only their own
287
- domain artifacts inside their substrate — never boards, ledgers, or run-state.
288
-
289
- Role → model, resolved once at GATE L0.8 from the `orch`/`exec`/`eval`/`qa` matrix
290
- (`harness verify t0` is mechanical tooling run directly via Bash, never an Agent — zero LLM
291
- tokens):
292
-
293
- | Skill | L0.8 role | Why this tier |
294
- |-------|-----------|---------------|
295
- | translator | exec | one-shot text transform — builder tier |
296
- | orient (Scout) | exec | reads/spikes code — builder tier, not judgment |
297
- | ba-pitch-analyzer | exec | planner — builder tier, not judgment |
298
- | scope-architect | exec | scope-contract author (sole writer of scopes/*.md) — builder tier |
299
- | task-executor | exec | the builder itself |
300
- | spec-evaluator | eval | the single judge (judge ≠ doer) — keep its own matrix key even if a PO points it at the same model as `exec`, so it can be split later without a harness change |
301
- | qa-edge-hunter | qa | cheapest tier by design — exploratory breadth over depth |
302
- | scope-hammer | exec | census + baseline comparison, proposes only — not a verdict |
303
- | coach | exec | categorization gate, not a verdict |
304
-
305
- The tech lead itself is `orch` — this conversation, never delegated to.
306
-
307
- The order is **Orient (7) → Map Scopes (8) → Build (9) → Eval**, faithful to Shape Up: the
308
- team orients before any board exists, so the planner's board is reality-born. The tech lead
309
- is the **sole writer of run-state** (`harness-run.md`) — it passes each worker the run
310
- metadata it needs (`feature`, `spec`, `stack`, `discovered_rounds`, `--auto`) as **args**;
311
- workers keep only their own product-idempotency key and emit domain artifacts.
312
-
313
- ## 0. LANGUAGE GATE → translator (GATE L0, only if non-English)
314
- ```
315
- Invoke via Agent (model: exec), BEFORE init run: Skill(shapeup-sdlc-plugin:translator) --check "<intake path>" "<breadboard path>"
316
- # detect-only, writes nothing
317
- English → skip; ORIENT against the original.
318
- non-English → Agent (model: exec): Skill(shapeup-sdlc-plugin:translator) "<intake path>" "<breadboard path>" [--auto]
319
- # full pass — the pitch AND its breadboard, before init run
320
- Writes: <name>.en.md per file (English copy; original untouched) + glossary.md
321
- + translation-report.md.
322
- Open the run on the .en.md pitch: init run stages breadboard.en.md beside it,
323
- and every planning worker reads what init run pinned — never a later copy.
324
- Read back: the detect table (--check) / the .en.md path + residual scan result (full pass).
325
- Authority: translator normalizes language only — it does not orient/plan/build/judge. The tech
326
- lead never translates itself; it only detects and sequences this step before ORIENT.
327
- ```
328
-
329
- ## 1. ORIENT → orient (the Scout, step 7) — runs BEFORE planning
330
- ```
331
- Invoke via Agent (model: exec): Skill(shapeup-sdlc-plugin:orient)
332
- --pitch "<kicked-off pitch path>" --spec <path> --stack "<hint>" [--auto]
333
- Owns: its own GATE O-A/O-B (or runs straight through under --auto)
334
- Writes: .shapeup/<slug>/orient/ → code-surface.md, spike-<area>.md, discovered-seed.md, hill-signal.md (LOCAL run-trace)
335
- Read back: hill-signal.md (render the area-level Hill at GATE L1a) + the spiked area/result.
336
- Why first: at Orient time NO board exists; the Scout's map + discovered seed make the planner's
337
- board reality-born instead of imagined. The four artifacts are the orient→ba contract.
338
- Authority: pure worker — no code, no board, no run-state, no reporting.
339
- ```
340
-
341
- ## 2. MAP SCOPES → ba-pitch-analyzer + scope-architect (step 8, orient-informed)
342
- ```
343
- Order A (the spec tree + board):
344
- compile-order --operation analyze --slug <slug> --worker ba-pitch-analyzer
345
- --payload '{"pitch": "<path>", "breadboard": "<the path init run printed, when it printed one>", "lens": "<lens>", "orient_dir": ".shapeup/<slug>/orient/"}'
346
- Agent (model: exec): Skill(shapeup-sdlc-plugin:ba-pitch-analyzer) --order <path>
347
- The order hands it code-surface.md (Phase-1 ingest, no re-scan), discovered-seed.md (task
348
- gen from reality), spike-<area>.md (feasibility/contracts).
349
- Writes (its substrate): spec_folder → _index.md, domain-model.md, ux-behavior.md, usecases/*,
350
- contracts/*.contract.md, scope-summary.md (+ api-feasibility.md if third-party) and the
351
- Returns: WorkResult (artifacts list + discoveries) → ingest-result.
352
- Order B (the scope contracts):
353
- compile-order --operation map-scopes --slug <slug> --worker scope-architect
354
- Agent (model: exec): Skill(shapeup-sdlc-plugin:scope-architect) --order <path>
355
- Writes (its substrate): shapeup/<slug>/scopes/*.md + scope-board.md — sole
356
- writer. Lint mechanically: node "${CLAUDE_PLUGIN_ROOT}/kernel/harness.mjs" verify spec <slug> (PA1/PA2 +
357
- substrate disjointness + the spec anchor: SCOPE-ANCHOR/TIER-DIRECTION/SCOPE-DEPS) before GATE L1b.
358
- Read back: .shapeup/<slug>/tasks/_index.md (the board) + scope-summary.md (Done-when)
359
- + the spec-lint verdict.
360
- Pass-through rule: do not coach the planner to over-specify implementation — keep tech high-level.
361
- ```
362
-
363
- ## 2b. RECONCILE → ba-pitch-analyzer (discovered task reconciliation, operation: reconcile)
364
- ```
365
- compile-order --operation reconcile --slug <slug> --worker ba-pitch-analyzer
366
- --payload '{"discovered_ledger": ".shapeup/<slug>/discovery/ledger.md"}'
367
- Agent (model: exec): Skill(shapeup-sdlc-plugin:ba-pitch-analyzer) --order <path>
368
- Effect: reconciles raw ledger discoveries into board tasks + appended UC invariants/TS rows,
369
- inside the reconcile write-contract (frozen zone enforced by the sandbox hook, not
370
- prose). Appetite Guard runs mechanically: node "${CLAUDE_PLUGIN_ROOT}/kernel/harness.mjs" reduce board.
371
- Returns: WorkResult → ingest-result (which updates the board and bumps discovered_rounds in
372
- harness-run.md — the worker holds no counter).
373
- Read back: updated tasks/_index.md + scope-summary.md before routing back to GATE L1b.
374
- ```
375
-
376
- Agent (model: exec): Skill(shapeup-sdlc-plugin:ba-pitch-analyzer) --order <path>
377
- Effect: regenerates the LOCAL task board fresh from the committed usecases/domain-model/scopes
378
- — no ledger, no reconciliation. Status bootstraps from committed T0/hill facts at
379
- SCOPE granularity; unlocks recomputed by node "${CLAUDE_PLUGIN_ROOT}/kernel/harness.mjs" reduce board --write.
380
- Read back: the freshly regenerated tasks/_index.md before entering BUILD.
381
- ```
382
-
383
- ## 3. BUILD → task-executor (always through the envelope port)
384
- ```
385
- r=1 loop:
386
- compile-order --next --slug <slug> [--test-cmd "<cmd>"] # exit 2 = no ready task
387
- Agent (model: exec), one fresh subagent per order:
388
- Skill(shapeup-sdlc-plugin:task-executor) --order <path>
389
- ingest-result <results/<id>.json> # ticks ACs, marks done, updates board, propagates unblocks
390
- Repeat until compile-order --next reports no ready task (board all ✅).
391
-
392
- r>1 (fix) per bug:
393
- compile-order --task <id> --slug <slug> --operation fix --payload '{"bugs": [<entries>]}'
394
- → dispatch + ingest as above. Scope the change to the bug only.
395
-
396
- Scope contracts present (isolated attempt loop, per scope, per attempt):
397
- compile-order --scope shapeup/<slug>/scopes/<id>.md --round <N> --attempt <M>
398
- → orders/r<N>-a<M>.json inlines the scope contract, this scope's tasks, promoted ledger
399
- decisions, the previous attempt's AEGIS triples, and `trial_history` — the last 8 trials
400
- for this scope (score, status, delta, top-3 digest), CROSSING the round boundary so a fix
401
- round cannot re-propose a change the build round already reverted. The zero-memory
402
- handoff, compiled from facts only. Dispatch a fresh Agent per attempt (the isolation
403
- boundary):
404
- Skill(shapeup-sdlc-plugin:task-executor) --order <path>
405
- ingest-result — a WorkResult with status "escalated" leaves its artifact unwritten → see 3b below.
406
-
407
- Read back: ingest-result's summary line (tasks updated, ACs ticked, unblocked, discoveries) — not raw board
408
- files. SPIKE tasks close before the tasks they block can build (compile-order enforces the
409
- dependency order).
410
- ```
411
-
412
- ## 3b. A worker that cannot finish (scope contracts present, mid-attempt)
413
- ```
414
- There is NO adjudication dispatch. A worker has no port for "I cannot decide this": WorkResult
415
- carries no escalates field, so the question never reaches you as data.
416
- What you see: the phase produces no artifact. The workflow's post-condition
417
- (harness probe resume --require <phase>) fails and the run ABORTS, naming the phase.
418
- Do: read the phase's result file to find what it could not complete, resolve it yourself —
419
- by amending the spec, widening the scope contract, or answering the ambiguity in the
420
- round-ledger "Decisions" table — then relaunch. The fast-forward re-dispatches only
421
- what is still unfinished.
422
- Why it aborts rather than pauses: nothing persists an answer between launches, so a pause
423
- would relaunch into the same order and hit the same wall. Aborting puts the question
424
- in front of a human once instead of looping silently.
425
- ```
426
-
427
- ## 3b.1 The other reason `--require`/`--set-status` fail: the check never ran
428
- ```
429
- The abort message names an exit code. `probe resume --require` documents exit 0 (satisfied) or
430
- 6 (artifact genuinely absent) as its only two real answers — anything else means the
431
- mechanical courier's Bash call was denied before the kernel script ever ran, most often
432
- an untrusted workspace or Claude Code's own auto-mode classifier flagging the courier's
433
- --require/--set-status pattern as gate-manipulation. Neither layer is this plugin's own
434
- hook, so neither leaves a row in .shapeup/<slug>/decisions.jsonl.
435
- What you see: the same-shaped abort as 3b, but the artifact IS actually on disk — the abort
436
- message now says so (exit_code shown, courier's own detail quoted) instead of asserting
437
- "the worker most likely escalated".
438
- Do: verify the phase's artifact by hand before trusting either diagnosis. If it exists, the
439
- phase is done; either relaunch (the classifier's denial is not guaranteed to repeat) or
440
- drive the remaining phase's kernel commands directly rather than through the Workflow —
441
- this is what routes around a blocked relaunch without waiting on the classifier.
442
- ```
443
-
444
- ## 3c. T0 verify → `harness verify t0` (skill-local; scope contracts present, every attempt)
445
- ```
446
- Invoke via Bash directly — NOT an Agent, this is deterministic tooling, not a worker:
447
- node "${CLAUDE_PLUGIN_ROOT}/kernel/harness.mjs" verify t0 shapeup/<slug>/scopes/<scope-id>.md
448
- --round <N> --attempt <M>
449
- Effect: runs the scope's e2e fixtures and DB probe. Writes the verdict artifact spec-evaluator's
450
- T0-citation rule will require a citation to, appends one row to t0/trials.jsonl, and — this
451
- is the ratchet — scores the attempt against the last kept trial and snapshots or
452
- restores the working tree ITSELF. Zero LLM tokens — deterministic tooling, not a
453
- judge (this is what keeps "T1 once per round" true even though verification runs
454
- every attempt).
455
- Read back: the stdout JSON — {path, sha256, trial, overall, regression, score, status,
456
- baseline_trial, delta, tree_ref}. `status` (kept|reverted|rebased|crash) is what
457
- drives the attempt-loop branch in protocol.md "Isolated attempt loop"; by the
458
- time you read it the tree action has already happened. Never branch on the process
459
- exit code: it carries the T0 binary (0 green / 1 red / 2 bad argv, the oracles/*
460
- convention), so a `kept` red-but-improved attempt, the ratchet's own signature case,
461
- exits 1. On red, its `discovered_tasks` field is
462
- the AEGIS digest to fold into the next brief — no separate digester dispatch needed
463
- (harness verify t0 calls its sibling harness probe digest internally on failure).
464
- ```
465
-
466
- ## 3d. Round build gate → `harness verify build` (once per round, before EVAL)
467
- ```
468
- Invoke via Bash directly — deterministic tooling, not a worker:
469
- node "${CLAUDE_PLUGIN_ROOT}/kernel/harness.mjs" verify build --slug <slug> --round <N>
470
- Effect: runs, in order and stopping at the first failure, the ledger's `run_cmd` (the build), then
471
- project-profile.md's `build_probe` (the built artifact covers what the run wrote — a green
472
- exit code is not proof the feature compiled when the toolchain compiles only what an entry
473
- point reaches) and `launch_probe` (install, start, assert the first screen, fail on fatal
474
- logs). Writes .shapeup/<slug>/build/r<N>-t<T>.json, immutable per run of the gate.
475
- Read back: stdout JSON — {overall: green|red, steps[], warnings[], failed_step?, stderr_tail?}.
476
- Exit 0 green · 1 red · 3 nothing declared (no run_cmd, no probes — logged, never green).
477
- A `mobile` profile with no launch_probe is warned about on stderr every round, and so is
478
- every scope none of whose fixtures invoke the tool run_cmd builds with — advisory, because a
479
- green T0 from such fixtures is not evidence the scope compiles.
480
- Preflight form — the same steps, run once before anything is dispatched, WRITING NOTHING:
481
- node "${CLAUDE_PLUGIN_ROOT}/kernel/harness.mjs" verify build --slug <slug> --preflight
482
- stdout JSON {preflight: true, status: green|red|cannot-run|undeclared, steps[], failed_step?,
483
- stderr_tail?}. Exit 0 green · 1 a step red · 4 a probe could not run (it exited 2 — no
484
- device, no artifact) · 3 nothing declared. No round artifact: a red preflight read back as
485
- round 0's gate would reach round 1's orders as bugs. The workflow warns on 1 and 4, never
486
- aborts.
487
- Consequences, both mechanical and both read off the artifact, never off this prose:
488
- red → EVAL is not dispatched this round; `harness compile` turns each failing step into a
489
- `payload.bugs` entry for round N+1, addressed to the scope whose substrate holds the
490
- files the tool's output names (unowned → every scope, marked).
491
- red → `reduce hill` withholds DOWNHILL_EXECUTION from every T0-green verdict of round N.
492
- ```
493
-
494
- ## 4. EVAL → spec-evaluator (once per round)
495
- ```
496
- compile-order --operation evaluate --slug <slug> --worker spec-evaluator --round <r>
497
- --payload '{"dimensions": ["spec-conformance"], "run_cmd": "<cmd>"}'
498
- t0_artifacts is compiled from each scope's green T0 verdict for round <r> — pass it only to
499
- override. A scope with no green verdict is named on stderr: the judge has nothing to cite for it.
500
- build_gate and launch_cmd are compiled too: this run's newest round build gate artifact, and the
501
- profile's launch_probe. Neither is passed here — a `[ui]` row is graded on the running app, and
502
- these are how the judge finds out the app was launched and how to bring it up again.
503
- Invoke via Agent (model: eval), ONCE, after GATE L2:
504
- Skill(shapeup-sdlc-plugin:spec-evaluator) --order <path>
505
- Effect: one feature-level pass over the running app against all AC + Done-when; writes
506
- evaluation/EVAL-FEATURE-<slug>.md (verdict + bug list) + its WorkResult (criteria
507
- verdicts, refuted boxes, T0 citations). It touches NO task file and NO board.
508
- ingest-result <results/evaluate-r<r>.json>: appends the .verdicts JSONL ledger, un-ticks the
509
- refuted AC boxes, sets eval_verdict frontmatter — the judge returns data, ingest writes.
510
- A verdict on a scoped spec that cites no T0 artifact, or a PASS that does not name
511
- every Test Surface row as its own criterion, is refused and the round stays open:
512
- re-dispatch the evaluator once with the refusal's reason, do not advance the round.
513
- Read back: EVAL-FEATURE-<slug>.md → verdict (pass|fail) + the bug list (each bug has
514
- task ref, severity, file:line, expected vs actual).
515
- ```
516
-
517
- > Dependency note: this uses spec-evaluator's **feature-level** pass (`--feature <slug>`),
518
- > which evaluates the whole board in one session rather than one task at a time. If your
519
- > installed spec-evaluator is the per-task v0.1, add the `--feature` mode (a small v0.2
520
- > patch: iterate the board's AC/Done-when in one probe+grade session, emit one
521
- > EVAL-FEATURE report) before wiring the tech lead to it. The per-task invocation still
522
- > works for ad-hoc checks, but the round loop expects one feature pass.
523
-
524
- ## 5. SHIP / GATE H → scope-hammer
525
- ```
526
- Invoke via Agent (model: exec): Skill(shapeup-sdlc-plugin:scope-hammer)
527
- --slug <slug> [--baseline <path>] [--breaker outer|inner --scope <id>]
528
- Effect: GATE H0 census (scopes + QA findings + discovered ledger + advisor-overflow flags) →
529
- H1 baseline comparison (never vs. a perfect ideal) → H2 cut list + verdict.
530
- Read back: the proposed cut list + verdict (SHIP now | SHIP after fixing ship-blocking items |
531
- CANNOT SHIP). The tech lead records the PO's decision in round-ledger.md and performs
532
- the actual close (SHIP S.1 onward) — scope-hammer proposes, it never ships.
533
- ```
534
-
535
- ## Authority boundaries (do not cross)
536
- - The Scout orients; it never plans, builds, or judges — it hands raw material to the planner.
537
- - The planner decides scope; the tech lead confirms it with the PO at GATE L1b.
538
- - The generator reports task outcomes in its WorkResult; `harness reduce ingest` flips `status:
539
- done` from that report. The tech lead confirms the feature-level close at GATE L4.
540
- - The evaluator issues verdicts only; it never closes tasks. Judge ≠ doer.
541
- - The tech lead decides *when* and *whether* each skill runs and how rounds proceed, owns
542
- run-state + the Hill report — it does not decide *what* a task contains or *whether* a
543
- single AC passes.
544
-
545
- ## Handoff files (the shared state)
546
- | File | Written by | Read by |
547
- |------|-----------|---------|
548
- | `<name>.en.md` + `glossary.md` | translator (L0, if non-English) | tech lead (ORIENT input), Scout, planner |
549
- | `orient/code-surface.md` | Scout (step 7) | planner Phase 1 (ingest, no re-scan) |
550
- | `orient/spike-<area>.md` | Scout (step 7) | planner Phase 1b/contracts; tech lead (L1a) |
551
- | `orient/discovered-seed.md` | Scout (step 7) | planner Phase 6 (task gen) |
552
- | `orient/hill-signal.md` | Scout (step 7) | tech lead (renders L1a Hill) |
553
- | `orders/<id>.json` (WorkOrder) | **harness compile (mechanical)** | every worker (its ONLY pipeline input), validate-envelope hook |
554
- | `results/<id>.json` (WorkResult) | the dispatched worker (its ONLY pipeline output) | harness reduce ingest (the single writer of everything below it) |
555
- | `.shapeup/<slug>/tasks/*` (LOCAL board, v3.2) | **harness reduce ingest** (status, AC ticks, unblocks) + planner orders (task bodies) | tech lead (board status), compile-order (next task, ACs) |
556
- | `discovery/ledger.md` | **harness reduce ingest** (from workers' `discoveries[]`) | reconcile orders (ba), scope-hammer (H0 census) |
557
- | `scope-summary.md` | planner (analyze/reconcile orders) | tech lead (Done-when), evaluator (Done-when criteria) |
558
- | `evaluation/EVAL-FEATURE-<slug>.md` + `.verdicts-*.jsonl` | evaluator (report) / **harness reduce ingest** (verdict ledger, un-ticks) | tech lead (verdict), next fix order (bug list) |
559
- | `harness-run.md` | **tech lead (sole writer)** | tech lead (round ledger + Hill + run-state), PO (audit) |
560
- | `scopes/<scope-id>.md` | `scope-architect` (sole writer) | tech lead (substrate/sequence), sandbox hook (write-whitelist), compile-order (inlined into orders) |
561
- | `t0/verdicts/r<N>-a<M>-t<T>.json` | `harness verify t0` (skill-local, mechanical — not a worker) | spec-evaluator (required citation), tech lead (hill derivation), compile-order (digested errors) |
562
- | `build/r<N>-t<T>.json` (the round build gate) | `harness verify build` (mechanical — run_cmd + build_probe + launch_probe, once per round before EVAL) | tech lead (GATE L2 block), `harness reduce hill` (a red round moves no dot), compile-order (`payload.bugs` for round N+1 when red; `payload.build_gate` on the same round's evaluate order) |
563
- | `t0/trials.jsonl` (the ratchet ledger, append-only, `baseline_trial` as the parent link) | `harness verify t0` (one row per attempt: score, status, delta, tree_ref) | compile-order (`trial_history` into the next order), ship-report (T0 + Ratchet sections), `harness probe stats --ratchet` |
564
- | `round-ledger.md` | **tech lead (sole writer)** | compile-order (decisions into every order), PO (audit) |
565
- | `hill/<scope-id>.yml` + `hill-chart.md` | **tech lead (sole writer)** | PO ("status without asking"), scope-hammer (H0 census) |
566
-
567
- > The single-writer rule is closed mechanically: no worker writes `run-state.md`, the board, or the ledger. A worker
568
- > performing a shared-state write is a defect — route it back through its WorkResult.
569
-
570
- ---
571
-
572
- # Part 3 — The invariants
573
-
574
- Moved out of `SKILL.md` when the round loop became a launchable script:
575
- most of what this table used to guard against — a partial board reaching EVAL, a gate crossed
576
- on the model's own authority, an evaluator called mid-BUILD — is now a property of
577
- `skills/tech-lead/workflows/shapeup-run.js`'s code, not a rule a model has to remember to obey.
578
- The table stays as the readable rationale for WHY the code is shaped the way it is; the runtime
579
- guarantee lives in the script and, where noted, in a hook.
580
-
581
- | Rule | Rationale |
582
- |------|-----------|
583
- | Orchestrates Building only (steps 7–11); shaping/betting/kick-off are PO-personal, upstream | Intake is a kicked-off pitch, not a raw idea — the tech lead does no shaping/planning-authority work |
584
- | ORIENT (step 7) runs before MAP SCOPES (step 8) | Roadmap: no pre-divided tasks at kick-off; the team orients first so the board is reality-born |
585
- | Intake must be English before ORIENT; tech lead does NOT translate — it delegates to `translator` at GATE L0 | Translation is a separate single-purpose skill; the intake conversation only detects + sequences it, before RunArgs is ever compiled |
586
- | Every worker dispatch goes through the envelope port: compile-order → `--order` → ingest-result; shared state is written ONLY by ingest | The single-writer rule is mechanically true: a worker that writes boards/ledgers/run-state is a defect, and a malformed envelope is denied by the validate-envelope hook before it can corrupt run truth. `shapeup-run.js` uses this same shape for every operation in the central registry — orient, wire, analyze, map-scopes, evaluate, hunt, hammer alike |
587
- | Progress is reported by Hill position, never by counting tasks | The roadmap forbids task-counting; a 90%-done slice can still be stuck uphill on the one unknown that matters |
588
- | Evaluator runs once per round, only after GATE L2 (board 100% done) | The whole point: cheap end-of-round QA, never per task. `shapeup-run.js`'s round loop dispatches spec-evaluator exactly once per iteration, after the GATE L2 resolution — there is no code path that calls it from inside the scope attempt loop |
589
- | Evaluator never called inside the BUILD loop | Keeps the build coherent and the run cheap |
590
- | r>1 builds bugs only, never the whole board | Don't re-do passing work; minimize churn — see protocol.md's regression rule for what DOES re-run (touched UCs' full Test Surface) |
591
- | Stop at max_rounds; escalate honestly | No infinite fix loops; `shapeup-run.js` returns `{status: "gate_h", breaker: "outer"}` rather than looping past the budget |
592
- | Tech lead delegates, never reimplements a sub-skill | Stays thin; each skill keeps its own gates and authority |
593
- | Every delegation to a sub-skill (except the mechanical `harness verify t0`/`harness compile`/`harness reduce ingest`) is a fresh Agent on the L0.8-resolved model | Isolation the zero-memory-handoff design assumes; a direct inline call would silently drop the model matrix — see references/protocol.md "Invocation mechanism" |
594
- | Planner stays high-level on tech | Spec errors cascade into every build round |
595
- | Never auto-deploy; "shipped" never silently means "deployed" | Deploy is outward-facing, PO-gated; record "deploy pending (PO)" otherwise |
596
- | "Shipped" names the dims NOT evaluated | `RunReturn`'s `dims_not_evaluated` field carries this; the L4 sign-off block shows it, never silently drops it |
597
- | Every gate emits the canonical `⏸ GATE LN — Title` block before any narrative | Composed by the workflow (`gateBlock()`), emitted VERBATIM by the skill — conversational re-summary is not a gate |
598
- | In interactive/--auto: a `paused` return stops and waits for PO confirmation | Never auto-proceed past a gate; the PO must cross each threshold explicitly — see "The pause protocol" in SKILL.md |
599
- | At GATE L3 FAIL: name scope (task + failed criterion), never prescribe fix options | Root cause analysis and fix paths belong to the implementer, not the orchestrator |
600
- | SHIP harvest records facts only — copies existing structured output, never computes a new verdict/score | A self-computed score = a second judge behind spec-evaluator (breaks single-judge, invites Goodhart); the eval suite interprets, harvest records |
601
- | Three-level circuit breaker: attempt_budget (inner, per scope) nests inside round_budget (outer), with an opt-in wall_clock_budget_s deadline | An exhausted scope queues a GATE H hammer proposal, it never blocks the round; only round_budget hitting 0 stops the whole run; the deadline breaker (checked every round boundary in `shapeup-run.js`) routes to GATE H so a run out of clock still ships what is green instead of being killed from outside |
602
- | The tech lead never hand-edits a scope contract | scope-architect is its sole writer (single-writer-per-file) |
603
- | Substrate-disjointness + PA1/PA2 lints are re-asserted at GATE L1b (harness verify spec) even when scope-architect already checked them | A human may have hand-approved past a 🔴 at the architect's checkpoint; `shapeup-run.js` runs spec-lint itself, in code, before resolving L1b |
604
- | Hill phase is read from mechanical facts (T0/T1), never declared by a worker | Closes the self-reported-confidence risk outright — facts move dots, not authors |
605
- | GATE H is delegated to scope-hammer, never adjudicated inline by the tech lead | Keeps the orchestrator thin; census/baseline-comparison/cut-list logic has one owner |
606
-
607
- ---
608
-
609
- # Part 4 — State
610
-
611
- Two halves of one question, folded into this file when the references consolidation retired the
612
- standalone `state.md`: who owns which artifact (state ownership), and the shape of what the tech
613
- lead itself writes — `harness-run.md`, the run's own ledger.
614
-
615
- ## State ownership (D6, mechanically closed in v1.0)
616
-
617
- Workers are stateless; the orchestrator layer is the **sole writer of ALL run-state**. Every
618
- worker receives a structured **WorkOrder** envelope (`.shapeup/<slug>/orders/`, compiled by
619
- `harness compile`) and returns a **WorkResult** envelope (`results/`); the deterministic
620
- `harness reduce ingest` performs every shared-state write — board status, AC ticks, unblock
621
- propagation, discovery-ledger appends, verdict bookkeeping.
622
-
623
- No worker writes `run-state.md`, `tasks/_index.md`, or the ledger. Everything a worker used to
624
- write into shared files, it now returns as data.
625
-
626
- The tech lead owns `harness-run.md` — rounds, gate decisions, Hill positions, verdicts,
627
- `discovered_rounds`, config, language record. The board (`tasks/_index.md`, LOCAL root — v3.2) is
628
- **execution truth**, maintained exclusively through ingest.
629
-
630
- **The run receipt (v1.4).** `harness init run` opens the run and writes
631
- `.shapeup/<slug>/receipt.json` plus `.shapeup/active-scope` before any gate. The
632
- receipt is the mechanical fact that a run *started* — distinct from every other artifact here,
633
- which records what a run *did*. That distinction is load-bearing: the guards that check a run's
634
- progress (the ship report's census) are all scoped to an active run, so before the receipt
635
- existed, a run that never started was invisible to every one of them. `hooks/gate-zerowork.mjs`
636
- reads only the receipt's presence, which is why it can see a total failure that leaves no other
637
- trace. See `references/gates.md` — GATE L0.1.
638
-
639
- ## Central domain registry
640
-
641
- Every record type and payload field that crosses a skill boundary is defined exactly once in
642
- `kernel/schemas/domain.schema.json` — the envelope schemas (`work-order.schema.json`,
643
- `work-result.schema.json`) only `$ref` it. The registry annotates each entity's tier
644
- (SHARED/LOCAL), location, sole writer, and readers, carries the machine-readable ERD (`x-erd`),
645
- and maps which payload fields each worker may rely on (`x-payload-by-worker`).
646
-
647
- A new cross-boundary field is added THERE first (structural test #24 enforces the map's
648
- consistency); a skill inventing its own undeclared field is a defect — the orchestrator, not the
649
- worker, owns the vocabulary.
650
-
651
- ## Two ledgers, split by promotion timing
652
-
653
- (Addendum §F.3 — only when scope contracts exist.)
654
-
655
- `harness-run.md` stays the LOCAL (`.shapeup/<slug>/`, gitignored) full run trace: it can be
656
- rebuilt or lost without consequence.
657
-
658
- A second, committed `round-ledger.md` (`shapeup/<slug>/round-ledger.md`, SHARED,
659
- Tier A) holds only what must survive a crash or a `.shapeup/` wipe:
660
-
661
- - the resolved model/budget matrix (L0.8/L0.9),
662
- - the **Decisions** table — every gate crossing and every PO answer to a blocked phase,
663
- promoted the instant it is given, never batched to round close.
664
-
665
- Gate crossings resolved from a **gate answer set** (`harness gate`) are written here
666
- with their source — `preset:ci`, `file:.shapeup/gate-answers.json` — and the set's
667
- `authorized_by`. A headless run that ships must always be able to name the human behind its
668
- sign-off; that name lives here and nowhere else.
669
-
670
- The tech lead is the sole writer of both. `round-ledger.md` is simply the subset that must never
671
- live only in a session or a gitignored file. No scope contracts → `round-ledger.md` is not
672
- written, and `harness-run.md`'s "Decisions log" is the only ledger, exactly as in v0.2.6.
673
-
674
- ## The ledger schema
675
-
676
- The tech lead's run record. One per feature, lives in the LOCAL run-trace root
677
- `.shapeup/<slug>/harness-run.md` (hidden, gitignorable — it is ephemeral run-state,
678
- not a shared deliverable). It is the structured
679
- artifact that carries state across rounds and across sessions (so `--from` can resume), and
680
- the PO's audit of how the feature was built.
681
-
682
- **The tech lead is the sole writer of this file.** It is the authoritative
683
- run-state for the whole build phase — rounds, gate decisions, Hill positions, verdicts,
684
- `discovered_rounds`, config, language record. Workers never write here; the tech lead passes
685
- them what they need (`feature`, `spec`, `stack`, `discovered_rounds`) as args. The board
686
- (`tasks/_index.md`) remains the planner/generator's execution truth that the tech lead reads.
687
-
688
- ## Frontmatter
689
- ```yaml
690
- ---
691
- type: harness-run
692
- feature: [slug]
693
- spec_folder: [path to SHARED spec deliverable, e.g. shapeup/<slug>/spec/]
694
- lens: lite | standard | cross-context
695
- eval_dimensions: auto # or the list from GATE L0.5 (init-run --dimensions); `auto` → each EVAL order resolves the set from the spec
696
- max_rounds: 3
697
- auto_level: interactive | auto | unattended
698
- status: orienting | mapping | building | evaluating | shipped | escalated | aborted
699
- final_verdict: ~ | pass | fail | not-evaluated
700
- rounds_used: [N]
701
- discovered_rounds: [N]
702
- deploy: ~ | deployed | pending-po
703
- started_at: [ISO]
704
- closed_at: ~ | [ISO]
705
- close_cause: ~ | [why the run ended at that terminal status — `probe resume --close` writes this and closed_at together]
706
- closed_status: ~ | [the terminal status actually closed — written ONLY by `probe resume --close`, never by `--set-status`, so it is immune to `status:` above being rewritten by ordinary phase traffic after the close]
707
- ---
708
- ```
709
-
710
- ## Round table (the spine)
711
- Mirrors the long-running harness cost table — one row per phase, so you can see where time
712
- and tokens go and that EVAL is cheap relative to BUILD.
713
-
714
- ```
715
- ## Rounds
716
- | Phase | Round | Result | Duration | Notes |
717
- |------------------|-------|-------------------|----------|-------|
718
- | Orient | — | spiked VNPay seam | 18 min | spike resolved; 9 discovered tasks seeded |
719
- | Map Scopes | — | 14 tasks, 5 layers| 5 min | orient-informed; 1 SPIKE (VNPay) |
720
- | Build | 1 | 14/14 ✅ | 2 h 10 m | all tasks closed |
721
- | Eval | 1 | FAIL — 3 bugs | 9 min | EVAL-FEATURE-checkout-vnpay.md |
722
- | Build | 2 | 3 bugs fixed | 22 min | bug-only re-build |
723
- | Eval | 2 | PASS | 8 min | verdict pass |
724
- | Ship | — | built & verified | — | dims: spec-conformance; deploy pending (PO) |
725
- ```
726
-
727
- ## Hill report (the progress narrative — NOT task counts)
728
- The roadmap forbids reporting progress by counting tasks: a 90%-done slice can still be stuck
729
- uphill on the one unknown that matters. So the tech lead reports each slice's **position on
730
- the hill**, derived mechanically from open unknowns. Render it at every round boundary
731
- (area-level at GATE L1a — before slices exist; slice-level from GATE L1b onward).
732
-
733
- ```
734
- ## Hill — round 1
735
- | Slice | Position | Derived from |
736
- |--------------|-------------|--------------|
737
- | S1-spine | 🔽 downhill | spike closed + spine render-AC passed (crest crossed); 2 known tasks left |
738
- | S2-filters | 🔼 uphill | SPIKE-003 open: pagination approach unproven |
739
- | S3-export | 🔼 uphill | contract ⏳ TBD: file-format field |
740
- ```
741
-
742
- Position triggers:
743
- - 🔼 **Uphill** — open SPIKE / `⏳ TBD` contract / unresolved discovered task / approach unproven.
744
- - ⛰️ **Crest** — all unknowns resolved AND a concrete board fact (the spine slice's render-AC passes).
745
- - 🔽 **Downhill** — only known work remains, no open unknowns.
746
- - ✅ **Done** — slice clickable-done.
747
-
748
- Source: `orient/hill-signal.md` (area-level, at L1a) then the board + open SPIKE/contract state
749
- (slice-level, L1b onward). If slice IDs aren't on the board yet, report at
750
- task-group level and note the fallback here.
751
-
752
- ## Decisions log
753
- Every L-gate decision, for traceability.
754
- ```
755
- ## Decisions
756
- - GATE L1a: Orient accepted; spiked VNPay seam (resolved); S2-filters flagged uphill.
757
- - GATE L1b: PO accepted board; cut "guest checkout" task to phase 2.
758
- - GATE L2 (r1): board green; ran eval (feature not trivial).
759
- - GATE L3 (r1): FAIL → approved bug-only round 2.
760
- - GATE L3 (r2): PASS → ship.
761
- - GATE L4: built & verified; deploy pending (PO); closed.
762
- ```
763
-
764
- ## Bug carry-over (when FAIL)
765
- Links the current round's bug list so the next BUILD round has its worklist.
766
- ```
767
- ## Open bugs (round 1 → fix in round 2)
768
- → see evaluation/EVAL-FEATURE-checkout-vnpay.md
769
- - BUG-1 critical SC-DONE-WHEN apps/web/checkout/Pay.tsx:84
770
- - BUG-2 major SC-ERR apps/api/payments/handler.ts:51
771
- - BUG-3 minor SC-NONGO apps/api/shared/auth.ts:12
772
- ```
773
-
774
- ## Escalation block (only if max_rounds hit without PASS)
775
- ```
776
- ## Escalation
777
- Rounds used: 3/3 — still FAIL. Residual bugs: [N].
778
- Recommendation: [cut scope of feature X | accept minor bugs | extend max_rounds with PO approval].
779
- Decision owner: PO.
780
- ```
781
-
782
- ## Rules
783
- - The ledger is append-mostly: each round adds rows, never rewrites history.
784
- - `status` + `final_verdict` are the resume anchors for `--from`.
785
- - A `not-evaluated` final verdict (from `--no-eval`) is recorded plainly — never silently
786
- upgraded to `pass`.
787
-
788
- ## `round-ledger.md` (committed, Tier A — scope contracts only)
789
-
790
- Lives at `shapeup/<slug>/round-ledger.md` (SHARED root, tracked). Not a replacement
791
- for `harness-run.md` — a small, committed **subset** of it: the two things that must survive
792
- a `.shapeup/` wipe or a crash. Absent on specs with no scope
793
- contracts; `harness-run.md`'s existing Decisions log stays the only ledger there.
794
-
795
- ```yaml
796
- ---
797
- type: round-ledger
798
- feature: [slug]
799
- models: # L0.8 resolved matrix, recorded once, source noted
800
- orch: [model] (source: flags|settings.local|settings.json|default)
801
- exec: [model] (source: ...)
802
- eval: [model] (source: ...)
803
- qa: [model] (source: ...)
804
- digester: script | sonnet
805
- budgets:
806
- round_budget: [N] # outer breaker
807
- attempt_budget: [N] # inner breaker, per scope
808
- ---
809
- ```
810
-
811
- ```
812
- ## Decisions
813
- | Round | Scope | Kind | Question | Answer | Resolved by |
814
- |-------|-------|------|----------|--------|-------------|
815
- | 2 | cart-creation | design-decision | cart-total rounding | round half-up | PO (interactive) |
816
- | 2 | cart-creation | substrate-expansion | needs packages/shared/http.ts | approved → shared_substrate | PO (interactive) |
817
- ```
818
- **Promotion timing:** a row is appended the INSTANT the PO answers —
819
- never batched to round close. This is the file `task-executor`'s isolated briefs read back
820
- (the zero-memory handoff): an answer given once in round 2 must still be known in round 5's
821
- fresh-context attempt without replaying any chat history.
822
-
823
- ## Harvest row — `metrics/<machine-id>.jsonl` (written at SHIP)
824
-
825
- `harness-run.md` is ephemeral run-state — needed live for `--from` resume, the
826
- FAIL-loop, and QA reconcile; worthless after ship. At SHIP the tech-lead **harvests**
827
- the durable-mineable *signals* out of it into one append-only row:
828
-
829
- ```
830
- .shapeup/metrics/<machine-id>.jsonl # one row = one e2e run; LOCAL (gitignored)
831
- ```
832
-
833
- Path note: `metrics/` lives under the LOCAL root with the rest of the run trace — moved
834
- there by ADR-0001, because a committed shard keyed on `$HOSTNAME` only grows and puts a
835
- person's machine name in the repo. It outlives any single run (the per-slug run dirs are
836
- superseded run by run; the shard only appends), which is what makes it the durable signal
837
- feed. Sharded per machine so shards can be pooled deliberately without colliding on one
838
- filename; the read plane is `harness probe stats`, or `cat .shapeup/metrics/*.jsonl`.
839
- `schema_version` makes an old row readable by later skill versions.
840
-
841
- ### Two hard rules (same discipline as the Test Surface: *derived, never invented*)
842
- 1. **Harvest only fields that already exist as structured output at ship time.** If a
843
- field forces the tech-lead to *evaluate something new* → reject (judgment in disguise).
844
- 2. **Harvest records facts, never computes a new verdict.** A self-computed
845
- `run_quality_score` would be a second judge behind `spec-evaluator` → breaks the
846
- single-judge rule and invites Goodhart. The eval suite *interprets* downstream;
847
- harvest *records*.
848
-
849
- Scope: the harvest feeds **only the e2e pipeline measurement**. The per-skill functional
850
- fixtures run in isolation and do not consume it.
851
-
852
- ### Row schema (one JSON object per line)
853
- | Field | Existing source (copied, never re-graded) | Signal |
854
- |---|---|---|
855
- | `schema_version` | constant `1` | forward-compat |
856
- | `run_id` | `receipt.json` (copied verbatim) | **the join key** — the row's only link to the run trace that produced it, and to the S.7 export. Every other field here is a count, and `feature_slug` groups two runs of one feature together rather than apart |
857
- | `feature_slug` | run-state frontmatter | identity |
858
- | `terminal_state` | run-state final: `shipped` / `circuit_broken` / `abandoned` | circuit-breaker outcome |
859
- | `round_count` | round table | effort-to-PASS |
860
- | `final_audit_score` | final EVAL report (copied, not re-graded) | conformance |
861
- | `surprise_count` | `.shapeup/<slug>/discovery/ledger.md` | shaping quality — scope drift |
862
- | `spike_unresolved_count` | `SPIKE-UNRESOLVED` markers at bet | shaping quality — open risk into bet |
863
- | `scope_cut_count` | `~` items cut at SHIP S.0 | appetite pressure / scope hammer |
864
- | `qa_findings` | `.shapeup/<slug>/qa/hunt-report.md` + triage → `{total, promoted, held}` | edge quality |
865
- | `slice_count` | `receipt.json` → `breadboard.ids.V` (the V# slices init run counted in the staged breadboard; omit the field when `breadboard` is null) | **normalizer / denominator** |
866
- | `sources` | path to each **SHARED** source artifact — never a LOCAL `.shapeup/` path (the run-trace is superseded run by run, so a LOCAL path dangles by the time anyone reads the row; SHARED paths resolve on any clone — tier-direction rule) | auditability |
867
-
868
- - `slice_count` is the **denominator**: `round_count=4` on a 2-slice feature is alarming,
869
- on a 9-slice feature is normal. Without it, e2e comparisons are apples-to-oranges.
870
- Enables `round-per-slice`, `surprise-per-slice`.
871
- - `spike_unresolved_count` + `surprise_count` measure two of the three downhill
872
- conditions (open-risk-remaining, scope-drift-from-breadboard). A good shaping run
873
- drives both toward 0 — measured from the build trace, no manual grading.
874
- - **Rejected fields:** `time_spent` / velocity (no clock; Shape Up forbids counting hours
875
- — `round_count` is the legitimate effort proxy) and `run_quality_score` (second judge).
876
- Even a real cost or wall-clock record would not belong here: a signal feed that carried a
877
- duration would become a velocity feed on the next person who read it. This harness does not
878
- currently carry one — the design called for one derived from a per-agent-call journal, but
879
- nothing in the pipeline ever writes it, so there is no such record to reject or admit.
880
-
881
- ### Row template
882
- ```json
883
- {"schema_version":1,"run_id":"checkout-vnpay-20260813T091233Z-c714ea8d","feature_slug":"checkout-vnpay","terminal_state":"shipped","round_count":2,"final_audit_score":"PASS","surprise_count":3,"spike_unresolved_count":0,"scope_cut_count":1,"qa_findings":{"total":5,"promoted":1,"held":4},"slice_count":4,"sources":["shapeup/checkout-vnpay/shaping/shaping.md","shapeup/checkout-vnpay/shaping/breadboard.md"]}
884
- ```
885
-
886
- LOCAL artifacts (the EVAL report, discovery ledger, QA hunt report) are *harvest-time reads*:
887
- their **values** are copied into the row's fields (`final_audit_score`, `surprise_count`,
888
- `qa_findings`) but their paths are never recorded in `sources` — they are gitignored and
889
- wiped, so a committed pointer to them is dead on arrival.