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
@@ -0,0 +1,69 @@
1
+ # Orders — what you write before every dispatch
2
+
3
+ An order is a JSON file at `.shapeup/<slug>/orders/<stem>.json`. It is checked against the order schema when the
4
+ dispatch leaves, and the write fence reads its `substrate` for as long as it has no result. Write it by copying the
5
+ template for the operation and filling the bracketed fields from the files named in the last column.
6
+
7
+ ## The envelope — the same for every operation
8
+
9
+ ```json
10
+ {
11
+ "schema_version": 1,
12
+ "order_id": "<slug>/<stem>",
13
+ "kernel": "<absolute path of this plugin copy's kernel entry point>",
14
+ "run_id": "<run_id from .shapeup/<slug>/receipt.json>",
15
+ "compiled_at": "<any ISO time; `order open` replaces it with the real one>",
16
+ "worker": "<orient | task-executor | spec-evaluator | qa-edge-hunter | building>",
17
+ "mode": "orchestrated",
18
+ "operation": "<orient | execute | fix | evaluate | hunt | plan>",
19
+ "interaction": { "pause_gates": false },
20
+ "substrate": { },
21
+ "payload": { }
22
+ }
23
+ ```
24
+
25
+ `compiled_at` is not yours to get right: `order open` overwrites it with the clock, because the fence compares it with the result's age and a time typed by hand that runs ahead of the clock keeps the order live after its worker returned. `kernel` is the absolute path, never a variable: a worker runs it as a command, and a command that spells it through a
26
+ variable is refused in a headless session. A `plan` order takes `"worker": "building"` and `"mode": "standalone"` —
27
+ no sub-agent answers it, it only opens the fence.
28
+
29
+ The stem is the file name without `.json`: `orient`, `plan-<step>`, `<scope>-r<R>-a<A>`, `evaluate-r<R>`, `hunt`. The
30
+ order's own `order_id` is `<slug>/<stem>`, and the result is written to `results/<stem>.json`. **An order with no result is
31
+ live**, and a live order keeps its substrate in force — so a worker that never answers stays fenced until the run is
32
+ re-opened with `--force` or the result lands.
33
+
34
+ ## Substrate per operation
35
+
36
+ `allowed` is what the worker may write; `shared` is the sanctioned escape for a path two scopes declare;
37
+ `frozen` outranks everything; `own` is the worker's own result and bookkeeping, and only the dispatch that took the order may write it.
38
+
39
+ | Operation | `allowed` | `frozen` | `own` |
40
+ |---|---|---|---|
41
+ | `orient` | `.shapeup/<slug>/orient/**` | `shapeup/<slug>/spec/**` | `.shapeup/<slug>/results/orient.json` |
42
+ | `execute` / `fix` | the scope contract's `allowed_file_substrate` plus `.shapeup/<slug>/spikes/**`; `shared` = its `shared_substrate` | `.shapeup/<slug>/**` | `results/<stem>.json`, `.shapeup/<slug>/tasks/TASK-*.md`, `.shapeup/<slug>/discovery/**`, `.shapeup/<slug>/spikes/**` |
43
+ | `evaluate` | none | `shapeup/<slug>/spec/**`, `.shapeup/<slug>/**` | `.shapeup/<slug>/evaluation/**`, `results/evaluate-r<R>.json` |
44
+ | `hunt` | none | `shapeup/<slug>/spec/**`, `.shapeup/<slug>/**` | `.shapeup/<slug>/qa/**`, `results/hunt.json` |
45
+ | `plan` (`requirements`) | `shapeup/<slug>/requirements.md` | the spec's domain model, use-case Steps, contracts, UX file; the run's intake, orders, results, receipts and T0 verdicts | `results/plan-requirements.json` |
46
+ | `plan` (`spec`) | `shapeup/<slug>/spec/**`, `.shapeup/<slug>/tasks/**`, `.shapeup/<slug>/working/**` | the intake, project profile, orders, results, receipts, T0 verdicts | `results/plan-spec.json` |
47
+ | `plan` (`wire`) | `shapeup/<slug>/wiring-map.md` | as `requirements`, plus `shapeup/<slug>/scopes/**` | `results/plan-wire.json` |
48
+ | `plan` (`scopes`) | `shapeup/<slug>/scopes/*.md`, `shapeup/<slug>/scope-board.md` | as `requirements`, plus `.shapeup/<slug>/tasks/**` | `results/plan-scopes.json` |
49
+
50
+ **Answer an order before you write the next one.** An order with no result is live, and a live `plan` order freezes `orders/**` — so writing the next order while the last is unanswered is refused by the fence. Write the result first, then the next order.
51
+
52
+ A needed file outside the table is the PO's decision, not yours: widen a scope's substrate by amending its contract, then write the order again.
53
+ Do not widen an order to make a worker's escalation go away.
54
+
55
+ ## Payload per operation
56
+
57
+ Pass a path wherever a path will do; a worker reads files, and an embedded copy goes stale.
58
+
59
+ | Operation | Payload | Where each field comes from |
60
+ |---|---|---|
61
+ | `orient` | `pitch`, `feature`, `spec_folder`, `kb_rules_path` | the intake path; the slug; the launch record's spec folder; `shapeup/knowledge-base/orient.md` if it exists |
62
+ | `execute` | `scope_contract` (path of `<spec>scopes/<id>.md`), `tasks` (`[{id, body_path}]` for the scope's tasks), `verify.test_cmd`, `kb_rules_path`, `round` | the scope file; the board's tasks whose `scope_id` is the scope; the contract's `e2e_verification_fixtures`; `shapeup/knowledge-base/task-executor.md` |
63
+ | `fix` | as `execute`, plus `bugs`, `digested_errors`, `trial_history` | the last verdict's FAIL criteria addressed to this scope's files; the failing lines of the last T0 verdict; the scope's rows in `t0/trials.jsonl`, oldest first, at most 8 |
64
+ | `evaluate` | `spec_folder`, `feature`, `dimensions`, `run_cmd`, `t0_artifacts`, `build_gate`, `round` | the spec path; the slug; the dimensions the PO named at L0, else the set the spec calls for (a Test Surface turns on test-surface-conformance, Invariants turn on completeness); the project profile's run command; the paths of each scope's latest `t0/verdicts/*.json` for the round; the note you wrote from your own build and launch this round (`.shapeup/<slug>/build/r<R>.md`: each step's command, exit code and output tail), omitted when you ran none |
65
+ | `hunt` | `feature`, `spec_folder`, `eval_report`, `app_url`, `round`, `kb_rules_path` | the slug; the spec path; the PASS evaluation report; the running app, or `null` for a deliverable that is not served |
66
+ | `plan` | `step`, `feature`, `spec_folder`, `kb_rules_paths` | the substep; the slug; the spec path; the knowledge-base files `resources/guidance.md` lists for planning |
67
+
68
+ A scope that did not go green in the round has its test-surface rows graded FAIL: name it in an `evaluate` order's `scopes_without_t0` rather than leaving the judge to find the gap.
69
+ A criterion the last verdict graded FAIL reaches the next round whether or not the judge filed a bug for it — a FAIL verdict with nothing to fix is how a run stalls.
@@ -59,7 +59,7 @@ When upgrading `lite → standard`:
59
59
  - `ux-behavior.md` stays authoritative for screen specs
60
60
  - Use cases are **reconciled** (API boundary sub-section added, not overwritten)
61
61
  - `contracts/` generated from reconciled UC API sub-sections
62
- - Reconciled files reported in the WorkResult's `deviations[]`
62
+ - Reconciled files are told to the PO when the spec step closes
63
63
 
64
64
  ---
65
65
 
@@ -118,7 +118,7 @@ Every task at Layer N depends on all relevant tasks at Layer N-1.
118
118
 
119
119
  ## Lens-Aware Task Layer Breakdown
120
120
 
121
- The layer structure differs by lens. Read the order's `payload.lens` for the active lens
121
+ The layer structure differs by lens. Read the step's `inputs.lens` for the active lens
122
122
  before generating tasks.
123
123
 
124
124
  ### LITE — Mobile-first layer breakdown
@@ -165,7 +165,7 @@ Errors → [[contracts/[repo].contract.md#Error-Cases]]
165
165
  ```
166
166
 
167
167
  Do NOT overwrite existing Steps section — append API Contract sub-section only.
168
- Report reconciled files in the WorkResult's `deviations[]` with note `reconciled-by-upgrade`.
168
+ Tell the PO which files were reconciled (`reconciled-by-upgrade`) when the spec step closes.
169
169
 
170
170
  ---
171
171
 
@@ -361,8 +361,8 @@ Slug rules:
361
361
  ## Link-Field Integrity (v3.3)
362
362
 
363
363
  **`depends_on` is the single authoritative edge; `unlocks` is derived, never hand-authored.**
364
- On EVERY board write — analyze, reconcile — recompute (via
365
- `harness reduce board --write`, never by hand) the `unlocks` field of every task on the board as the
364
+ On EVERY board write — a full spec step, a reconcile — recompute (from the whole board, every time — never
365
+ by feel) the `unlocks` field of every task on the board as the
366
366
  exact inverse of the full board's `depends_on` graph, then write it. Adding one task that
367
367
  declares `depends_on: [TASK-007]` therefore rewrites `TASK-007.unlocks` in the same pass.
368
368
  "Write both sides when you remember" allows drift; a derived field cannot drift
@@ -516,9 +516,9 @@ Non-Go:
516
516
 
517
517
  ---
518
518
 
519
- ## Discovered-Task Reconciliation (operation: reconcile)
519
+ ## Discovered-Task Reconciliation (spec substep, mode: reconcile)
520
520
 
521
- Used by the reconcile operation over the discovered ledger at a round boundary. This is a pure
521
+ Used by the spec substep in `reconcile` mode over the discovered ledger at a round boundary. This is a pure
522
522
  reducer: read existing state + the ledger delta, emit new state. The pitch and the
523
523
  upfront DDD layer are FROZEN — this mode never re-runs Phase 1–5.
524
524
 
@@ -531,8 +531,8 @@ tasks). Scope (Basecamp sense) maps onto a UC; an invariant lives *inside* the U
531
531
  1. Verify the ledger belongs to this spec. A discovered ledger rarely carries a pitch_hash
532
532
  (its frontmatter names the raw materials, e.g. source: shaping.md + breadboard.md).
533
533
  So match on identity that DOES exist:
534
- a. ledger.feature == run-state.feature (REQUIRED — mismatch → STOP)
535
- b. if ledger carries pitch_hash, it must == run-state.pitch_hash
534
+ a. ledger.feature == this run's feature slug (REQUIRED — mismatch → STOP)
535
+ b. if ledger carries pitch_hash, it must == the staged pitch's hash
536
536
  Neither resolvable → STOP: "ledger does not match this spec (different feature slug)."
537
537
  2. READ-ONLY for the frozen zone: domain-model, usecases/ (Steps), ux-behavior, contracts/.
538
538
  3. Parse ledger scopes → map each to its owning UC (S1→UC-…, S2→UC-…, S3→UC-…).
@@ -545,7 +545,7 @@ tasks). Scope (Basecamp sense) maps onto a UC; an invariant lives *inside* the U
545
545
  [ ] already has a file → skip
546
546
  5. For a Keep item that asserts a new invariant on its scope's UC:
547
547
  APPEND an [INV-NN] line to that UC's ## Invariants section (append-only,
548
- never touch Steps/Input/Output). Log the UC path in run-state.human_edited_files.
548
+ never touch Steps/Input/Output).
549
549
  Generate the regression task with command-verifiable AC (see AC Trigger Matrix).
550
550
  6. Number new tasks by reading max id in tasks/_index.md and incrementing.
551
551
  NEVER renumber existing tasks — that would break every depends_on wikilink the
@@ -563,7 +563,7 @@ tasks). Scope (Basecamp sense) maps onto a UC; an invariant lives *inside* the U
563
563
  task-executor / the tech lead; this mode only surfaces the disagreement.
564
564
  9. Regenerate ONLY the derived files: tasks/_index.md, scope-summary.md, synthesis.md
565
565
  (+ the unlocks frontmatter recompute from step 7).
566
- 10. Run harness reduce board (Appetite Guard arithmetic, below); report overflow as a discovery.
566
+ 10. Do the Appetite Guard arithmetic below over the whole board; report overflow as a discovery.
567
567
  ```
568
568
 
569
569
  **Appetite Guard (forcing function, not a report):**
@@ -584,7 +584,7 @@ This is scope hammering at the gate boundary — the overflow is surfaced, never
584
584
  **Naming note:** the discovery ledger's "scope" sections (above) predate the formal Scope
585
585
  Contract artifact below and name the same thing — a `discovery/ledger.md` scope heading MUST
586
586
  match an existing `scope_id` from a `scopes/<scope-id>.md` contract, or (a Keep item
587
- introducing new flow) become the seed for a new one via a scope-architect `map-scopes` order. One concept, two touch points.
587
+ introducing new flow) become the seed for a new one via the scopes substep. One concept, two touch points.
588
588
 
589
589
  **Import/flow slicing (PA1 countermeasure).** Build a lightweight import graph over the task
590
590
  board's touched files: for each file a task writes, note what it imports and what imports it
@@ -614,8 +614,8 @@ or entirely `apps/api/**` with no cross-layer flow is the PA1 failure mode — r
614
614
  }
615
615
  ```
616
616
  `hill_phase` is always written `UPHILL_UNKNOWN` at generation time — it is derived later from
617
- mechanical T0/T1 facts, never declared by `ba`. `superseded_by` stays
618
- `null` until a scope-architect `map-scopes` order retires this contract in favor of its replacements.
617
+ mechanical T0/T1 facts, never declared by the planner. `superseded_by` stays
618
+ `null` until the scopes substep retires this contract in favor of its replacements.
619
619
 
620
620
  **PA2 size lint:** a scope whose `allowed_file_substrate` glob set resolves to more than ~15
621
621
  files gets a ⚠️ from spec-lint PA2 (hard-cap configurable via pitch frontmatter `scope_size_cap`, default
@@ -35,7 +35,7 @@ gap → surface it at GATE 4 as a question (max 2 rule applies), do not silently
35
35
 
36
36
  ```markdown
37
37
  ## Test Surface
38
- <!-- DERIVED — regenerate via a retrofit-surface order; do not hand-author rows here.
38
+ <!-- DERIVED — regenerate via a retrofit-surface spec step; do not hand-author rows here.
39
39
  Source must cite D1–D4. Exploratory/edge tests live in QA's charters, not here. -->
40
40
  | ID | Oracle | Probe | Expect | Source |
41
41
  |---|---|---|---|---|
@@ -82,17 +82,16 @@ gathered, never *who* decides.
82
82
 
83
83
  1. **Phase 4 (fresh run, v2.9+):** derived per UC immediately after Error Cases are
84
84
  written, included in the GATE 4 review.
85
- 2. **retrofit-surface operation (retrofit, incremental reducer):** for pre-v2.9 specs.
86
- Frozen-zone discipline identical to the reconcile operation (the order's substrate enforces it):
85
+ 2. **retrofit-surface mode of the spec substep (retrofit, incremental reducer):** for specs that predate the Test Surface.
86
+ Frozen-zone discipline identical to the reconcile mode (the plan order's substrate enforces it):
87
87
  - READ-ONLY: domain-model, UC Steps/Input/Output/Invariants, ux-behavior, contracts/, tasks/
88
88
  - WRITE: append `## Test Surface` to each UC (after Error Cases; skip UCs that already
89
- have one unless `--force-surface`), log touched UCs in `run-state.human_edited_files`,
90
- set `run-state.test_surface: true`. Regenerate nothing else.
89
+ have one unless `--force-surface`), tell the PO which UCs were touched. Regenerate nothing else.
91
90
  - Source material missing (no Invariants, no contracts on lite) → derive from what
92
91
  exists; a UC whose four sources are all empty gets a one-line section:
93
92
  `_No derivable surface — sources empty. Exploratory coverage only (see qa-edge-hunter)._`
94
- 3. **reconcile operation:** when a new `[INV-NN]` is appended to a UC, also
95
- append its `TS-INV-NN` row (same append-only discipline, same `human_edited_files` log).
93
+ 3. **reconcile mode:** when a new `[INV-NN]` is appended to a UC, also
94
+ append its `TS-INV-NN` row (same append-only discipline).
96
95
 
97
96
  ## Audit hooks (spec-lint)
98
97
  - L2: every UC (v2.9 spec or `test_surface: true`) has `## Test Surface` with ≥1 row or the
@@ -0,0 +1,95 @@
1
+ # Plan — the scope contracts
2
+
3
+ **Slice by flow, never by directory — and write it as a contract a hook can enforce.** Groups a feature's
4
+ tasks into independent, vertically-sliced **scopes** and writes each as a committed contract,
5
+ `shapeup/<slug>/scopes/<scope-id>.md`, that the rest of the harness enforces mechanically: the sandbox
6
+ hook denies writes outside a substrate, the T0 verifier runs the fixtures, the evaluator asserts only
7
+ against the affordance manifest. This substep is the sole writer of scope contracts and of `scope-board.md`
8
+ (`scope-summary.md` belongs to the spec substep).
9
+
10
+ Inputs: the board's tasks with their touched files — the slicing INPUT only. Each carries `use_case_refs`;
11
+ those use-case ids are what you write into the contract, never a task id. Also: `ux-behavior.md` for the
12
+ affordance manifests, the use cases for flows, the breadboard when present (every U# the spec places is one
13
+ manifest entry's `source`; record which scopes deliver each V# slice in `scope-board.md`), and the guidance
14
+ files (slicing habits for this codebase, config files that must have exactly one owner, fixtures that have
15
+ proved vacuous — steering, never spec: a guideline cannot widen a substrate or stand in for the lint;
16
+ conflict → the spec and the lint win, told to the PO).
17
+
18
+ ## Process
19
+
20
+ ```
21
+ 0 READ the guidance, if any exists.
22
+ 1 SLICE build an import/business-flow graph over the tasks' touched files (a grep heuristic is fine; an
23
+ AST is an optimisation). One scope = one call chain: the UI screen + the API route + the use
24
+ case + the repository it drives. A scope aligned 1:1 with a top-level directory (all-frontend,
25
+ all-backend) FAILS — that is layer-thinking.
26
+ 2 CLASSIFY topology_type: LAYER_CAKE (thin balanced UI + backend) | ICEBERG (complexity on one side) |
27
+ CHOWDER (true strays with no shared flow — the one deliberate exception).
28
+ 3 CONTRACT per scope, write scopes/<scope-id>.md — MARKDOWN: frontmatter for scalars and [a, b] lists, a
29
+ `## Affordances` table for the affordance manifest, a short `## Why this slice` paragraph. A
30
+ reviewer must be able to read the substrate in a PR; regeneration preserves prose under
31
+ headings you do not own.
32
+ 4 READ BACK the contracts together, once, and say what you found: PA1 (a scope aligned 1:1 with a top-level
33
+ directory), PA2 (> ~15 files, a warning), DISJOINT (a file in two scopes' substrate without both
34
+ declaring it shared — the write fence enforces substrates, so an overlap here is a collision there),
35
+ SCOPE-ANCHOR (empty or unresolvable use_cases), SCOPE-DEPS (depends_on naming a scope that is not
36
+ here). Fix reds by re-slicing, not by silencing. A task id in a committed contract is refused by the
37
+ write fence itself.
38
+ 5 BOARD regenerate scope-board.md — a VIEW of the contracts, nothing more:
39
+ | scope_id | topology | use_cases | depends_on | files | lint |
40
+ Every column restates a field the contract already declares, so the board can be thrown away and
41
+ rebuilt. Do NOT add a `wave` column: waves are Kahn levels of `depends_on`, derived at dispatch;
42
+ a hand-written copy of a derived value drifts, which is why `unlocks` stopped being authored.
43
+ The BUILD ORDER lives in each contract's `depends_on`; the board only shows it.
44
+ ```
45
+
46
+ ## The contract's fields
47
+
48
+ | Field | Rule |
49
+ |---|---|
50
+ | `scope_id`, `topology_type` | the stable join key is the scope id |
51
+ | `use_cases[]` | the use-case ids this scope implements — **the ONLY link you write to the work: never task ids.** The contract is committed and the board is not, so a task id here dangles on every other clone (TIER-DIRECTION reds it). The scope's tasks are re-derived from the board's own `use_case_refs` |
52
+ | `covers[]` | optional REQ-ids from `requirements.md` this scope answers for. Write the registry's own key — `REQ-12`, not the pitch's `R12`: both resolve, but one spelling in the committed contract is one thing to read |
53
+ | `depends_on[]` | scope ids this scope builds AFTER — the build ORDER. Declare it whenever one scope consumes another's output, or the two race: nothing infers it, and an undeclared edge releases both into the same wave |
54
+ | `allowed_file_substrate[]` | exact globs; the sandbox hook's write whitelist. Wrong here = a legitimate escalation later |
55
+ | `shared_substrate[]` | files ≥ 2 scopes both touch. Declaring one costs concurrency: they build one at a time |
56
+ | `affordance_manifest` | from the `ux-behavior.md` state tables: every interactive element as `{test_id, role}` + `required_states` [idle, loading, success, error, empty] + `source`, the U# the ux row cites |
57
+ | `e2e_verification_fixtures[]` | the command(s) / spec file(s) that drive this scope end to end (the T0 layer). Too speculative to fixture → mark TBD and flag it, never invent a fixture for unbuilt behavior. **Every fixture MUST EXIT 0 when the scope is correct** — T0 scores any non-zero exit as a failure, so a bare error-path invocation can never pass; put expected non-zero exits inside a test file that itself exits 0, and name that file. Write them as a FRONTMATTER key holding bare commands |
58
+ | `hill_phase` | `"UPHILL_UNKNOWN"`, ALWAYS; phase is derived from T0/T1 facts later, never authored |
59
+
60
+ **`affordance_manifest` lives in the TABLE and NOWHERE ELSE.** Do not also write it in the frontmatter:
61
+ nothing reads it there, so the copy is discarded — and a run has been lost to exactly that (the frontmatter
62
+ said `required_states: [idle]`, the table cell said a bare `idle`, the table won, the value was a string
63
+ where an array was required, and four scopes were never dispatched with every check green). A contract
64
+ declaring no affordances writes `affordance_manifest: []` in frontmatter and no table.
65
+
66
+ **A list inside a table cell is written `[a, b]`, brackets and all** — `[idle]`, never `idle`. A bare word in
67
+ that cell is a string, and `required_states` is an array.
68
+
69
+ A `TASK-` id anywhere in a contract or the board — a column, a cell, a sentence of prose — is TIER-DIRECTION
70
+ red. The board is committed; task ids are not.
71
+
72
+ **Folding in a discovered item:** it joins the nearest scope only if the flow matches (extend that substrate
73
+ minimally); otherwise propose a NEW scope — never silently widen an existing one. **Re-slicing a stuck
74
+ scope:** re-run step 1 on just that scope's task and file set → N new contracts; mark the old one
75
+ `superseded_by: [ids]` — never delete (the branch and the T0 history stay attributable).
76
+
77
+ ## Reasons not to cut a corner
78
+
79
+ | Excuse | Reality |
80
+ |---|---|
81
+ | "The discovered item obviously fits scope A" | Run the flow match. "Obviously" is how substrates silently widen. |
82
+ | "One scope per directory is cleaner" | That is PA1 — a layer, not a flow. A scope must ship something a user can do. |
83
+ | "I'll widen the substrate so the doer stops escalating" | A wide substrate is no substrate. Split, or add a `shared_substrate` entry, deliberately. |
84
+ | "This scope looks downhill, I'll set the phase" | `hill_phase` is `UPHILL_UNKNOWN` at write, always. Facts move dots, not authors. |
85
+ | "The old contract is superseded, delete it" | Supersede, never delete. History must stay attributable. |
86
+ | "Both scopes implement that use case, the tasks will sort themselves out" | They will not — both get every task of that use case and three of four writes get denied. Give each scope its own use cases, or tell the PO. |
87
+ | "I'll list the task ids so the contract says what it builds" | The board is gitignored and renumbers per machine; the contract is committed. Cite the use cases. |
88
+ | "Fixtures can come later" | A fixture at contract time or an explicit TBD flag — silence is how T0 goes blind. |
89
+
90
+ Verify before `close`: every scope crosses layers or is declared CHOWDER (PA1 = 0 red); every scope names ≥ 1
91
+ `use_cases` that resolves on disk and no contract carries a task id; every scope that consumes another's
92
+ output declares it in `depends_on`; substrates are disjoint except declared `shared_substrate`; every
93
+ interactive element in a scope's screens appears in exactly one manifest; every U# the spec places is some
94
+ manifest entry's `source`; every scope has fixtures or an explicit TBD flag; every `hill_phase` written is
95
+ `UPHILL_UNKNOWN`; superseded contracts are kept.
@@ -0,0 +1,102 @@
1
+ # Plan — the spec tree and the board
2
+
3
+ Converts the pitch into a fully linked tree: `_index` → `domain-model` → `ux-behavior` → `usecases/` →
4
+ `integration` → `tasks/`, with Obsidian wikilinks and a shared frontmatter taxonomy, navigable from pitch to
5
+ atomic task. Formats live in `plan-references/` (the rules each phase follows) and `plan-templates/` (one
6
+ template per document).
7
+
8
+ **Modes.** `full` (the default) writes the whole tree and the board. `board-only` — the tree is already
9
+ committed and FROZEN; the board is per-machine and is not on this machine — regenerates `tasks/` from the
10
+ use cases as they are: the same task derivation, every acceptance criterion carrying its
11
+ `(covers: REQ-…)` clause, ids numbered fresh for this machine. In `board-only` never touch the spec folder,
12
+ re-derive or "improve" a use case, or invent a task no use-case step or Test Surface row sources.
13
+
14
+ Payload the step may carry: `lens` (`lite` | `standard` | `cross-context`; absent → judge it: LITE for a
15
+ ≤ 2-week appetite, no third party, ≤ 3 user-facing actions; STANDARD for multi-team, third-party or bigger;
16
+ genuinely unclear → one binary question to the PO), the pitch, the breadboard (its Places are your screens;
17
+ its U# and N# are the affordances you place and cite — absent = none separate, never inferred) and the
18
+ orient directory.
19
+
20
+ ## The pipeline (mode `full`)
21
+
22
+ Read the reference file before its phase; pause for the PO at a checkpoint only when the run is
23
+ interactive, at most two questions each.
24
+
25
+ ```
26
+ 1 INGEST pitch + breadboard + orient artifacts + guidance. Extract slug, appetite, in/out boundaries,
27
+ rabbit holes, third-party mentions. With a breadboard, list every Place (P#) and UI
28
+ affordance (U#) first — they are the screens and interactive elements phase 3 must place.
29
+ No files written yet.
30
+ 1b FEASIBILITY (third-party / API / SDK / webhook mentioned) verification questions + a fallback scope per
31
+ API-NN → api-feasibility.md
32
+ 2 DDD bounded contexts, aggregates (new vs extended), value objects, domain events, repository
33
+ interfaces → domain-model.md [plan-references/ddd-patterns.md]
34
+ 2b CONTRACTS (standard lens) typed Request/Response/Error per repository; two-pass rule: unresolvable at
35
+ spec time → `⏳ TBD — verify in the [UC-x] spike`, resolved post-spike with a citation →
36
+ contracts/ [plan-references/contract-patterns.md]
37
+ 3 UX per screen — with a breadboard, one screen per Place that owns UI affordances: state table
38
+ (idle → loading → error → success), error cases with message + action, ASCII flows →
39
+ ux-behavior.md [plan-references/ux-behavior-patterns.md]
40
+ 4 USE CASES one file per actor + action: typed Input/Output, numbered Steps, all error cases with
41
+ codes, ## System Flow (UI → API → UC → Repo → DB), ## Test Surface (DERIVED ONLY from
42
+ D1 Invariants · D2 Error Cases · D3 Contract shape · D4 No-gos — a sourceless test idea is
43
+ a spec gap to raise, never a row to invent) → usecases/ [plan-references/test-surface.md]
44
+ 5 INTEGRATION (standard lens) cross-system data flows, events, silent-failure risks → integration.md
45
+ [plan-references/integration-analysis.md]
46
+ 6 TASKS atomic, ordered, executable → tasks/ (the LOCAL root, the one uncommitted branch of the
47
+ tree: regenerable, machine-local) [plan-references/task-generation.md]
48
+ 7 DERIVE+READ BACK not yours to grade, and no script does it for you:
49
+ recompute `unlocks` as the depends_on inverse over the whole board; sum the hours; find the
50
+ critical path; do the appetite arithmetic — an overflow is a fact you REPORT for the stop
51
+ gate, never resolve. Then read the tree back: structure, wikilinks, edge symmetry — fix what
52
+ you find. BREADBOARD-PLACE / BREADBOARD-UI: every Place with UI affordances is its own
53
+ screen — add it or defer the Place with the PO's yes; never fold it into another
54
+ → scope-summary.md + synthesis.md (traceability matrix, risk register, dependency graph —
55
+ the judgment layers over the board's numbers)
56
+ 8 INDEX _index.md (pitch digest + document map) + feedback.md template
57
+ ```
58
+
59
+ Working notes (`scope-summary.md`, `synthesis.md`, `assess-report.md`, `feedback.md`, `api-feasibility.md`,
60
+ `integration.md`) live in the LOCAL tier since the consumer layout split: the committed `spec/` keeps what
61
+ the evaluator grades against and a reviewer needs.
62
+
63
+ ## Task generation rules (what makes a task executable)
64
+
65
+ - One task = one verifiable change (one package, one concern); acceptance criteria checkable by running
66
+ commands.
67
+ - `depends_on` explicit; `unlocks` is the `depends_on` inverse, recomputed whenever a task changes, never filled in by feel.
68
+ - Contract-first: an implementation task touching a repository requires its contract file (else generate
69
+ the contract-stub task first); third-party + `⏳ TBD` → the SPIKE task precedes and blocks it
70
+ (`time_box_hours` hard cap, `api_ref`, `blocks[]`).
71
+ - AC trigger matrix (full rules in `plan-references/task-generation.md`): conditional rendering → 🔁
72
+ Inverse Conditions; data fetching → 📭 Empty & Null States; numeric limits → 🔢 Boundary Values; FEAT +
73
+ a user actor or cross-layer → 🧪 BDD Scenarios; ≥ 1 service boundary → 🔗 Integration Flow; not
74
+ triggered → remove the section entirely.
75
+ - After all implementation tasks: one integration-test task (DB round-trip, auth rejection, cross-service
76
+ BDD).
77
+
78
+ **Coverage trust = use case.** Every task carries `use_case_refs`; a task with none is an orphan (red). An
79
+ invariant-backed regression task still anchors to its owning use case — there is no second path to green.
80
+
81
+ **The requirement edge is written on the AC line, or it does not exist.** An acceptance criterion that
82
+ grades a registry requirement ends with `(covers: REQ-…)` — the trailing clause, in the checkbox text, not a
83
+ mention in prose. A board AC reaches the judge through the refuted list alone: it can yield a FAIL and can
84
+ never yield a PASS, so an AC nothing cites by id produces no evidence for the requirement it was written
85
+ for. A board whose criteria carry no `covers:` clause beside a registry is sent back once.
86
+
87
+ **A requirement with no natural use-case home still becomes a task.** Contrast, localisation, a
88
+ performance ceiling, a test surface — a non-functional clause has no actor + action and so no use case of
89
+ its own, and the habit is to record it in the risk register, where nothing grades it. Give it a task whose
90
+ AC reaches the committed spec (the invariant, the contract field or the Test Surface row that states it)
91
+ and carries its `(covers: REQ-…)`. A line in the risk table is a note; a covered AC is a requirement the
92
+ run can be measured against.
93
+
94
+ ## What is yours and what is not
95
+
96
+ You write the spec tree, the board and the working notes. You do not write `run-state` (dead — the loop
97
+ owns run truth), `tasks/_index.md` status flips for built work (the loop's, when it applies a result), scope contracts (the
98
+ scopes substep's), or any discovered-rounds counter. Verify before `close`: every task has
99
+ `use_case_refs`, explicit `depends_on`, command-verifiable acceptance criteria; no hand-authored `unlocks`;
100
+ `unlocks` was recomputed after the last board change; you read the tree back and found 0 red (or each remaining red
101
+ is explained to the PO); every Test Surface row cites a D1–D4 source (gaps raised, not filled); appetite
102
+ overflow, if any, is reported, not resolved.
@@ -65,7 +65,7 @@ audit_rules_version: "2.5"
65
65
 
66
66
  ## Audit Report
67
67
 
68
- *Generated from harness verify spec output — do not edit manually.*
68
+ *Written by the planning step from its own read-back — do not edit manually.*
69
69
  *skill_version: 2.1 | audit_rules_version: 2.1*
70
70
 
71
71
  ### Score Summary
@@ -83,17 +83,16 @@ This pitch touches N bounded contexts: [context-a], [context-b], [context-c]
83
83
 
84
84
  **Option A — Single standard run** *(faster, boundaries may be blurry)*
85
85
  ```bash
86
- /ba-pitch-analyzer --lens standard docs/pitch.md
86
+ # plan the spec step with lens=standard for docs/pitch.md
87
87
  ```
88
88
  Estimated tokens: ~N tokens
89
89
 
90
90
  **Option B — Split + cross-context** *(slower, precise boundaries)*
91
91
  ```bash
92
- /ba-pitch-analyzer --lens standard docs/pitch-[context-a].md
93
- /ba-pitch-analyzer --lens standard docs/pitch-[context-b].md
94
- /ba-pitch-analyzer --cross-context FEATURE_SLUG \
95
- shapeup/[context-a]/spec/ \
96
- shapeup/[context-b]/spec/
92
+ # plan the spec step with lens=standard for docs/pitch-[context-a].md
93
+ # plan the spec step with lens=standard for docs/pitch-[context-b].md
94
+ # then plan the cross-context documents (FEATURE_SLUG) over
95
+ # shapeup/[context-a]/spec/ and shapeup/[context-b]/spec/
97
96
  ```
98
97
  Estimated tokens: ~N total (reusable per context)
99
98
 
@@ -116,12 +115,12 @@ Choose: **[A]** or **[B]**
116
115
 
117
116
  ```bash
118
117
  # Proceed with recommended lens
119
- /ba-pitch-analyzer --lens LENS docs/pitch.md
118
+ # plan the spec step with lens=LENS for docs/pitch.md
120
119
 
121
120
  # Override lens
122
- /ba-pitch-analyzer --lens lite docs/pitch.md
123
- /ba-pitch-analyzer --lens standard docs/pitch.md
121
+ # plan the spec step with lens=lite for docs/pitch.md
122
+ # plan the spec step with lens=standard for docs/pitch.md
124
123
 
125
- # Skip assess on next run (pitch already reviewed)
126
- /ba-pitch-analyzer --lens LENS --skip-assess docs/pitch.md
124
+ # Skip the assessment on the next run (pitch already reviewed)
125
+ # plan the spec step with lens=LENS for docs/pitch.md
127
126
  ```
@@ -55,14 +55,14 @@ upgrade_adds: []
55
55
 
56
56
  ```bash
57
57
  # Check current upgrade options
58
- /ba-pitch-analyzer --status shapeup/FEATURE_SLUG/spec/
58
+ # re-read the spec and recompute `unlocks` over the board
59
59
 
60
60
  # Upgrade to standard lens (adds contracts + integration + full synthesis)
61
- /ba-pitch-analyzer --upgrade standard shapeup/FEATURE_SLUG/spec/
61
+ # re-plan the spec step with lens=standard over shapeup/FEATURE_SLUG/spec/ (extend, never overwrite Steps)
62
62
 
63
63
  # Upgrade specific module only
64
- /ba-pitch-analyzer --upgrade contracts shapeup/FEATURE_SLUG/spec/
65
- /ba-pitch-analyzer --upgrade synthesis shapeup/FEATURE_SLUG/spec/
64
+ # re-plan the spec step for the contracts only
65
+ # re-plan the spec step for the synthesis only
66
66
  ```
67
67
 
68
68
  ## Metrics
@@ -39,7 +39,7 @@ The longest sequential chain — minimum time to complete if parallelized optima
39
39
  *(All other work can happen in parallel alongside this chain)*
40
40
 
41
41
  <!-- Record the DERIVED numbers only — total hours and step count, both from
42
- `harness reduce board`. The chain's task ids belong to the LOCAL board
42
+ the board you recomputed. The chain's task ids belong to the LOCAL board
43
43
  (.shapeup/<slug>/tasks/), which is gitignored and renumbers per machine; this
44
44
  document is committed, so an id written here dangles on every other clone
45
45
  (spec-lint TIER-DIRECTION). Read the id-level chain off the board itself. -->
@@ -99,7 +99,7 @@ Carried from [[_index#Rabbit-Holes]]:
99
99
 
100
100
  ## Execution Recommendation
101
101
 
102
- <!-- Filled from harness verify spec output -->
102
+ <!-- Filled from the planning step's own read-back -->
103
103
 
104
104
  **Audit Score: N/100**
105
105
 
@@ -28,9 +28,9 @@ depends_on:
28
28
  |-----------|--------|--------|
29
29
  <!-- Coverage here is USE CASES × TASKS, derived by inverting each task's use_case_refs over the
30
30
  local board. It is NOT requirement coverage: whether every REQ-id reaches an acceptance
31
- criterion that a judge graded is a projection derived per run (`probe requirements`), and a
31
+ criterion that a judge graded is a projection read per run off the verdict and the `covers:` edges, and a
32
32
  committed file that states it is corroborating something no run measured. Name REQ ids in this
33
- row and spec-lint reds it (REQ-NARRATED). Count use cases and tasks; say nothing about REQ. -->
33
+ row and the claim goes stale the day it is written. Count use cases and tasks; say nothing about REQ. -->
34
34
  | Coverage | COVERAGE_STATUS | COVERAGE_SIGNAL |
35
35
  | Risk | RISK_STATUS | RISK_SIGNAL |
36
36
  | Dependency | DEPENDENCY_STATUS | DEPENDENCY_SIGNAL |
@@ -165,7 +165,7 @@ Derived from: `_index.md` rabbit holes + `api-feasibility.md` SPIKE blocks + `in
165
165
  <!--
166
166
  The SINGLE source of truth for tasks that were scope-hammered out of the cycle.
167
167
  A Cut produces NO task file (no bet yet, so no spec). Only record a trace line here.
168
- Mostly populated/appended by the reconcile operation over the discovered ledger.
168
+ Mostly populated/appended by the spec substep's reconcile mode over the discovered ledger.
169
169
  Each line: what was cut — Cut @ GATE-N · reason · (if hammer-traded) which task it was traded for.
170
170
  -->
171
171
 
@@ -194,6 +194,6 @@ spec-lint reds a `TASK-` id anywhere in the committed tree (TIER-DIRECTION).
194
194
  | Single points of failure (block > 2 downstream) | N |
195
195
 
196
196
  **The per-scope build order — which scopes go in which wave, and what each waits on — lives in
197
- `scope-board.md`, not here.** `scope-architect` writes that board and is the only worker that knows
197
+ `scope-board.md`, not here.** the scopes substep writes that board and is the only step that knows
198
198
  the scope ids; it runs after this document, so the ordering cannot be expressed here in a key that
199
199
  survives a clone. Cite the board, never restate it.
@@ -68,7 +68,7 @@ interface [UseCaseName]Output {
68
68
  An invariant must STILL hold after this UC is built.
69
69
  Each invariant is a source of regression tasks — that task anchors use_case_refs back to THIS UC
70
70
  (do NOT create a new anchor axis; an invariant is a property of the UC, not a UC of its own).
71
- This section MAY be APPENDED by the reconcile operation when a build discovers a new constraint
71
+ This section MAY be APPENDED by the spec substep's reconcile mode when a build discovers a new constraint
72
72
  (append-only — never edit the locked Steps/Input/Output).
73
73
  Drop this section if the UC produces no invariants.
74
74
  -->
@@ -86,7 +86,7 @@ interface [UseCaseName]Output {
86
86
  DERIVED section — generated mechanically from Invariants (D1) + Error Cases (D2) +
87
87
  Contract/Input shape (D3) + pitch No-gos touching this UC (D4).
88
88
  Rules → references/test-surface.md. Never hand-author rows; never invent behaviors.
89
- Regenerable via a retrofit-surface order. Appended-to (TS-INV rows) by the reconcile operation when
89
+ Regenerable via the spec substep's retrofit-surface mode. Appended-to (TS-INV rows) by its reconcile mode when
90
90
  a new invariant lands. Exploratory/edge tests do NOT live here (qa-edge-hunter owns those).
91
91
  If all four sources are empty, replace the table with:
92
92
  _No derivable surface — sources empty. Exploratory coverage only (see qa-edge-hunter)._