bigpowers 1.5.1 → 2.0.1

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 (49) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/CONVENTIONS.md +18 -2
  3. package/README.md +39 -13
  4. package/RELEASE.md +16 -1
  5. package/SKILL-INDEX.md +3 -3
  6. package/assess-impact/SKILL.md +2 -2
  7. package/build-epic/SKILL.md +5 -5
  8. package/change-request/SKILL.md +4 -4
  9. package/dashboard/src/loaders/reader.js +2 -1
  10. package/dashboard/src/tui/epic-queue.js +2 -0
  11. package/dashboard/src/tui/filesystem.js +5 -6
  12. package/dashboard/src/tui/index.js +39 -13
  13. package/dashboard/src/tui/ledger.js +3 -5
  14. package/dashboard/src/tui/metrics-bar.js +20 -3
  15. package/dashboard/src/tui/pipeline.js +9 -13
  16. package/dashboard/src/tui/state-yaml.js +6 -8
  17. package/deepen-architecture/SKILL.md +6 -6
  18. package/define-success/SKILL.md +1 -1
  19. package/develop-tdd/SKILL.md +3 -3
  20. package/elaborate-spec/SKILL.md +7 -7
  21. package/execute-plan/SKILL.md +4 -4
  22. package/investigate-bug/SKILL.md +1 -1
  23. package/kickoff-branch/SKILL.md +1 -1
  24. package/map-codebase/SKILL.md +4 -4
  25. package/migrate-spec/SKILL.md +8 -8
  26. package/model-domain/SKILL.md +8 -8
  27. package/orchestrate-project/REFERENCE.md +8 -4
  28. package/orchestrate-project/SKILL.md +2 -2
  29. package/package.json +1 -1
  30. package/plan-release/SKILL.md +73 -27
  31. package/plan-work/SKILL.md +23 -7
  32. package/release-branch/SKILL.md +15 -0
  33. package/research-first/SKILL.md +2 -2
  34. package/run-evals/SKILL.md +2 -2
  35. package/run-planning/SKILL.md +1 -1
  36. package/scope-work/SKILL.md +4 -4
  37. package/scripts/land-branch.sh +28 -0
  38. package/seed-conventions/SKILL.md +37 -6
  39. package/session-state/SKILL.md +34 -3
  40. package/slice-tasks/SKILL.md +4 -4
  41. package/survey-context/SKILL.md +2 -2
  42. package/trace-requirement/SKILL.md +6 -6
  43. package/verify-work/SKILL.md +35 -2
  44. package/write-document/SKILL.md +1 -1
  45. package/dashboard/src/data/gate-status.js +0 -32
  46. package/dashboard/src/data/metrics.js +0 -89
  47. package/dashboard/src/data/pipeline-map.js +0 -32
  48. package/dashboard/src/data/reader.js +0 -122
  49. package/dashboard/src/data/watcher.js +0 -108
@@ -20,8 +20,8 @@ model: sonnet
20
20
 
21
21
  ## Artefact
22
22
 
23
- `specs/EVALS-<feature>.md` — see [REFERENCE.md](REFERENCE.md) for template.
23
+ `specs/verifications/eNNsYY-eval-report.md` — see [REFERENCE.md](REFERENCE.md) for template. Eval reports are stored alongside verification evidence in `specs/verifications/`, keyed by story ID for traceability.
24
24
 
25
25
  ## Verify
26
26
 
27
- → verify: `ls specs/EVALS-*.md 2>/dev/null | head -1 | grep -q EVALS && echo OK || echo MISSING`
27
+ → verify: `find specs/verifications -name "*-eval-report.md" | wc -l | awk '{if($1>0) print "OK: "$1" eval reports"; else print "MISSING"}'`
@@ -5,7 +5,7 @@ description: Advance discover-phase workflows and update specs/planning-status.y
5
5
  ---
6
6
 
7
7
  # Run Planning
8
- > **HARD GATE** — **HARD GATE** — Before running planning skills, confirm the epic shard exists and the active story is clear. Planning without a target is noise.
8
+ > **HARD GATE** — **HARD GATE** — Before running planning skills, confirm the epic capsule exists and the active story is clear. Planning without a target is noise.
9
9
 
10
10
 
11
11
  Updates `specs/planning-status.yaml` as discover-phase skills complete.
@@ -1,22 +1,22 @@
1
1
  ---
2
2
  name: scope-work
3
- description: Define what is in and out of scope for the current effort and save as specs/requirements/SCOPE_LATEST.yaml. Use when user wants a PRD, scope definition, or before plan-release on a new initiative.
3
+ description: Define what is in and out of scope for the current effort and save as specs/product/SCOPE_LATEST.yaml. Use when user wants a PRD, scope definition, or before plan-release on a new initiative.
4
4
  model: sonnet
5
5
  ---
6
6
 
7
7
  # Scope Work
8
8
 
9
- Turn the current conversation into a bounded PRD at `specs/requirements/SCOPE_LATEST.yaml`.
9
+ Turn the current conversation into a bounded PRD at `specs/product/SCOPE_LATEST.yaml`.
10
10
 
11
11
  ## Process
12
12
 
13
13
  1. Read existing `specs/` artifacts (`release-plan.yaml`, `plans/TECH_STACK_LATEST.md`, `requirements/VISION_LATEST.yaml` if any).
14
14
  2. Interview (if needed): goal, users, in-scope, out-of-scope, constraints, success metrics.
15
- 3. Write `specs/requirements/SCOPE_LATEST.yaml` with: `core_value`, `summary`, `in_scope[]`, `out_of_scope[]`, `constraints`, `success_criteria`, `references`.
15
+ 3. Write `specs/product/SCOPE_LATEST.yaml` with: `core_value`, `summary`, `in_scope[]`, `out_of_scope[]`, `constraints`, `success_criteria`, `references`.
16
16
  4. Run `research-first` if external dependencies are proposed.
17
17
 
18
18
  > **HARD GATE** — Every `in_scope` item must map to a future epic/story ID or explicit deferred note in `out_of_scope`.
19
19
 
20
20
  ## Verify
21
21
 
22
- → verify: `test -f specs/requirements/SCOPE_LATEST.yaml && grep -c 'out_of_scope' specs/requirements/SCOPE_LATEST.yaml | awk '{if($1>0) print "OK"; else print "MISSING"}'`
22
+ → verify: `test -f specs/product/SCOPE_LATEST.yaml && grep -c 'out_of_scope' specs/product/SCOPE_LATEST.yaml | awk '{if($1>0) print "OK"; else print "MISSING"}'`
@@ -143,6 +143,34 @@ if git remote get-url origin >/dev/null 2>&1; then
143
143
  git push origin "$DEFAULT_BRANCH"
144
144
  fi
145
145
 
146
+ # Epic capsule archival (evolved bigpowers v4.0.0+)
147
+ # Move completed epic capsules to archive when all stories are done
148
+ echo "==> Checking for completed epic capsules to archive..."
149
+ if [ -d specs/epics ] && [ -f specs/execution-status.yaml ]; then
150
+ for capsule in specs/epics/e[0-9]*-*/; do
151
+ [ -d "$capsule" ] || continue
152
+ capsule_name=$(basename "$capsule")
153
+ epic_id=$(echo "$capsule_name" | grep -o '^e[0-9]*' || true)
154
+ [ -n "$epic_id" ] || continue
155
+ # Check if all stories in this epic are done
156
+ ALL_DONE=true
157
+ if [ -f "$capsule/epic.yaml" ]; then
158
+ for story_id in $(grep -o 'e[0-9]*s[0-9]*' "$capsule/epic.yaml" 2>/dev/null || true); do
159
+ STATUS=$(grep "$story_id:" specs/execution-status.yaml 2>/dev/null | awk '{print $2}' || echo "todo")
160
+ if [ "$STATUS" != "done" ]; then
161
+ ALL_DONE=false
162
+ break
163
+ fi
164
+ done
165
+ fi
166
+ if [ "$ALL_DONE" = true ]; then
167
+ mkdir -p specs/epics/archive
168
+ echo " Archiving completed epic: $capsule_name → specs/epics/archive/"
169
+ mv "$capsule" "specs/epics/archive/"
170
+ fi
171
+ done
172
+ fi
173
+
146
174
  # Worktree cleanup
147
175
  WORKTREE_PATH="../$FEATURE_BRANCH"
148
176
  if git worktree list --porcelain 2>/dev/null | grep -q "^worktree $WORKTREE_PATH$"; then
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: seed-conventions
3
3
  model: sonnet
4
- description: Generate CLAUDE.md and CONVENTIONS.md for a brand-new project through a brief interview, and create the specs/ directory. Entry point for greenfield projects. Use when starting a new project from scratch, when user asks to set up AI agent conventions, or when there is no CLAUDE.md yet.
4
+ description: Generate CLAUDE.md and CONVENTIONS.md for a brand-new project through a brief interview, and create the specs/ directory with evolved bigpowers structure (product/, tech-architecture/, verifications/, epics/archive/). Entry point for greenfield projects. Use when starting a new project from scratch, when user asks to set up AI agent conventions, or when there is no CLAUDE.md yet.
5
5
  ---
6
6
 
7
7
  # Seed Conventions
@@ -75,7 +75,7 @@ Stack: [language, framework, runtime]
75
75
  ## Agent Rules
76
76
  - **Workflow Mandate:** You MUST use the bigpowers skills (e.g. `plan-work`, `develop-tdd`, `orchestrate-project`) to perform tasks. DO NOT write code directly in response to a user prompt like "build this feature".
77
77
  - Read specs/ before writing code.
78
- - All planning and specifications MUST be written to `specs/` (`requirements/SCOPE_LATEST.yaml`, `release-plan.yaml`, `epics/`) before any code is generated.
78
+ - All planning and specifications MUST be written to `specs/` (`product/SCOPE_LATEST.yaml`, `release-plan.yaml`, `epics/`) before any code is generated.
79
79
  - Write the minimum code that solves the stated problem. Nothing extra.
80
80
  - Never refactor, rename, or reorganize code outside the task scope.
81
81
  - Run tests after every change. Show evidence before declaring done.
@@ -115,7 +115,7 @@ Stack: [language, framework, runtime]
115
115
  ## Agent Rules
116
116
  - **Workflow Mandate:** You MUST use the bigpowers skills (e.g. `plan-work`, `develop-tdd`, `orchestrate-project`) to perform tasks. DO NOT write code directly in response to a user prompt like "build this feature".
117
117
  - Read specs/ before writing code.
118
- - All planning and specifications MUST be written to `specs/` (`requirements/SCOPE_LATEST.yaml`, `release-plan.yaml`, `epics/`) before any code is generated.
118
+ - All planning and specifications MUST be written to `specs/` (`product/SCOPE_LATEST.yaml`, `release-plan.yaml`, `epics/`) before any code is generated.
119
119
  - Write the minimum code that solves the stated problem. Nothing extra.
120
120
  - Never refactor, rename, or reorganize code outside the task scope.
121
121
  - Run tests after every change. Show evidence before declaring done.
@@ -155,7 +155,7 @@ Stack: [language, framework, runtime]
155
155
  ## Agent Rules
156
156
  - **Workflow Mandate:** You MUST use the bigpowers skills (e.g. `plan-work`, `develop-tdd`, `orchestrate-project`) to perform tasks. DO NOT write code directly in response to a user prompt like "build this feature".
157
157
  - Read specs/ before writing code.
158
- - All planning and specifications MUST be written to `specs/` (`requirements/SCOPE_LATEST.yaml`, `release-plan.yaml`, `epics/`) before any code is generated.
158
+ - All planning and specifications MUST be written to `specs/` (`product/SCOPE_LATEST.yaml`, `release-plan.yaml`, `epics/`) before any code is generated.
159
159
  - Write the minimum code that solves the stated problem. Nothing extra.
160
160
  - Never refactor, rename, or reorganize code outside the task scope.
161
161
  - Run tests after every change. Show evidence before declaring done.
@@ -177,14 +177,45 @@ Use the standard bigpowers CONVENTIONS.md template, filling in the project-speci
177
177
 
178
178
  ### `specs/` directory
179
179
 
180
+ Create the evolved bigpowers directory structure:
181
+
180
182
  ```bash
181
- mkdir -p specs
182
- echo "# Specs\n\nAll planning documents for this project." > specs/README.md
183
+ mkdir -p specs/product
184
+ mkdir -p specs/product/snapshots
185
+ mkdir -p specs/epics/archive
186
+ mkdir -p specs/tech-architecture
187
+ mkdir -p specs/adr
188
+ mkdir -p specs/verifications
189
+ mkdir -p specs/bugs
190
+
191
+ # Create empty placeholder files
192
+ touch specs/product/SCOPE_LATEST.yaml
193
+ touch specs/product/VISION_LATEST.yaml
194
+ touch specs/product/GLOSSARY_LATEST.yaml
195
+ touch specs/release-plan.yaml
196
+ touch specs/execution-status.yaml
197
+ touch specs/planning-status.yaml
198
+ touch specs/state.yaml
199
+ touch specs/tech-architecture/tech-stack.md
200
+ touch specs/tech-architecture/security.md
201
+ touch specs/tech-architecture/test.md
202
+ touch specs/tech-architecture/design.md
203
+ touch specs/tech-architecture/REFACTOR_LATEST.md
204
+ touch specs/tech-architecture/IMPACT_LATEST.md
205
+ touch specs/bugs/registry.yaml
206
+ echo "# Specs\n\nAll planning documents for this project. Evolved bigpowers structure (v2.0.0+)." > specs/README.md
183
207
  ```
184
208
 
209
+ **Note:** `specs/state.yaml.lock` is NOT pre-created — it is acquired and released dynamically during writes to prevent concurrency conflicts.
210
+
185
211
  ### Verify
186
212
 
187
213
  - [ ] CLAUDE.md exists and is populated
188
214
  - [ ] CONVENTIONS.md exists and includes specs/ output convention
189
215
  - [ ] specs/ directory exists
216
+ - [ ] specs/product/ exists with SCOPE_LATEST.yaml, VISION_LATEST.yaml, GLOSSARY_LATEST.yaml
217
+ - [ ] specs/tech-architecture/ exists with tech-stack.md, security.md, test.md, design.md
218
+ - [ ] specs/verifications/ exists
219
+ - [ ] specs/epics/archive/ exists
220
+ - [ ] specs/bugs/registry.yaml exists
190
221
  - [ ] Confirm with user: "Does CLAUDE.md accurately describe your project?"
@@ -12,7 +12,7 @@ Track the current state of implementation, including decisions made, pending tas
12
12
 
13
13
  ## Goal
14
14
 
15
- Maintain a single source of truth for the *current* session in `specs/state.yaml`. This complements long-term docs in `specs/plans/` and delivery detail in `specs/epics/` + `specs/release-plan.yaml`.
15
+ Maintain a single source of truth for the *current* session in `specs/state.yaml`. This complements long-term docs in `specs/tech-architecture/` and delivery detail in `specs/epics/` + `specs/release-plan.yaml`.
16
16
 
17
17
  Legacy markdown (`specs/archive/STATE.md`, `RELEASE-PLAN.md`) is **not** SoT when YAML exists — use `specs/state.yaml` only.
18
18
 
@@ -45,7 +45,7 @@ handoff:
45
45
 
46
46
  If `specs/state.yaml` does not exist, or if starting a new major phase:
47
47
 
48
- - [ ] Read `specs/release-plan.yaml` and `specs/requirements/SCOPE_LATEST.yaml`.
48
+ - [ ] Read `specs/release-plan.yaml` and `specs/product/SCOPE_LATEST.yaml`.
49
49
  - [ ] Get git metadata: `git branch --show-current` and `git rev-parse --short HEAD`.
50
50
  - [ ] Create `specs/state.yaml` with active flow, git, handoff, and epic cycle if in build.
51
51
 
@@ -68,6 +68,32 @@ Whenever a significant decision is made or a milestone is reached:
68
68
 
69
69
  → verify: `bash scripts/validate-specs-yaml.sh`
70
70
 
71
+ ## State Write-Lock Protocol
72
+
73
+ > **HARD GATE** — Before any write to `specs/state.yaml` or `specs/execution-status.yaml`, acquire `specs/state.yaml.lock`. Release it immediately after the write. A stale lock (>60s) may be force-released.
74
+
75
+ ### Acquire
76
+
77
+ 1. Check if `specs/state.yaml.lock` exists.
78
+ 2. If it exists, read the agent ID and timestamp inside.
79
+ 3. If the lock is stale (>60s old), remove it and proceed.
80
+ 4. If the lock is fresh (<60s), wait 2s and retry (max 15 attempts = 30s).
81
+ 5. Write `agent_id: <name>\nacquired_at: <ISO-8601>` to `specs/state.yaml.lock`.
82
+
83
+ ### Release
84
+
85
+ 1. After the write to `state.yaml` or `execution-status.yaml` completes:
86
+ 2. `rm specs/state.yaml.lock`
87
+
88
+ ### Lock format (`specs/state.yaml.lock`)
89
+
90
+ ```yaml
91
+ agent_id: session-state
92
+ acquired_at: "2026-06-11T14:30:00Z"
93
+ ```
94
+
95
+
96
+
71
97
  ## Operations
72
98
 
73
99
  ### show-state (absorbed)
@@ -80,7 +106,12 @@ Clear ephemeral session state. Set `active_epic_id`, `active_story_id`, and `epi
80
106
 
81
107
  ### compact-state (absorbed)
82
108
 
83
- Archive verbose decisions before a context transition. Move all entries from `handoff.open_decisions` to `specs/adr/` as individual ADR files, then reset `handoff.open_decisions` to an empty list.
109
+ Archive verbose decisions before a context transition. Move all entries from `handoff.open_decisions` to their appropriate location:
110
+
111
+ - **System-wide decisions** → `specs/adr/NNNN-slug.md` (global Architectural Decision Records)
112
+ - **Epic-scoped decisions** → `specs/epics/<active_epic_id>-<slug>/adr/NNNN-slug.md` (epic-local ADRs, archived with epic)
113
+
114
+ After archiving, reset `handoff.open_decisions` to an empty list.
84
115
 
85
116
  ## File Format: specs/state.yaml
86
117
 
@@ -6,17 +6,17 @@ model: sonnet
6
6
 
7
7
  # Slice Tasks
8
8
 
9
- Produce **epic shard stories** in `specs/epics/eNN-*.yaml` — vertical slices, each independently deliverable and testable. Legacy `specs/epics/ (see slice-tasks)` is deprecated; use epics + `execution-status.yaml`.
9
+ Produce **epic capsule story tasks** in `specs/epics/eNN-slug/` — vertical slices, each independently deliverable and testable. Output: decoupled `eNNsYY-tasks.yaml` files with runnable verify commands. Legacy `specs/epics/ (see slice-tasks)` is deprecated; use capsule dirs + `execution-status.yaml`.
10
10
 
11
11
  ## Process
12
12
 
13
- 1. Read `specs/requirements/SCOPE_LATEST.yaml` and/or `specs/release-plan.yaml`.
13
+ 1. Read `specs/product/SCOPE_LATEST.yaml` and/or `specs/release-plan.yaml`.
14
14
  2. Cut **tracer-bullet slices** (thin end-to-end paths first, then depth).
15
- 3. Each story: `id` (e.g. `e03s01`), `title`, optional `depends-on` in task desc, `tasks[]` with `desc` + `verify`.
15
+ 3. Each story: writes `eNNsYY-tasks.yaml` with `story_id`, `title`, `status`, `bcps`, `tasks[]` (each with `id`, `description`, `verify`, `status`). Story spec `.md` files are written by `plan-work` and follow [countable-story-format.md](file:///Users/danielvm/Developer/bigpowers/countable-story-format.md).
16
16
  4. Order by WSJF in `release-plan.yaml` epic list.
17
17
 
18
18
  > **HARD GATE** — No horizontal-only slices ("add all models") without a vertical path that proves integration.
19
19
 
20
20
  ## Verify
21
21
 
22
- → verify: `grep -c 'id: e' specs/epics/*.yaml | awk '{if($1>0) print "OK"; else print "MISSING"}'`
22
+ → verify: `find specs/epics -name "*-tasks.yaml" | wc -l | awk '{if($1>0) print "OK: "$1" task files"; else print "MISSING"}'`
@@ -67,7 +67,7 @@ Based on what you've found, identify which PMBOK phase this project is currently
67
67
  | **Design** | SCOPE exists but no `release-plan.yaml` |
68
68
  | **Plan** | `release-plan.yaml` exists; on `main`/`master` branch |
69
69
  | **Initiate** | On a feature branch; no code changes yet |
70
- | **Execute** | `state.yaml` `active_flow: build_epic`; epic shard in progress |
70
+ | **Execute** | `state.yaml` `active_flow: build_epic`; epic capsule in progress |
71
71
  | **Verify** | Implementation done; run `verify-work` or `run-evals` |
72
72
  | **Bug** | `state.yaml` `active_flow: fix_bug` or open `specs/bugs/BUG-*.md` |
73
73
  | **Review** | All code written; no PR yet |
@@ -116,7 +116,7 @@ At story start, write `metrics.story_start` with the current ISO 8601 timestamp
116
116
 
117
117
  ### list-epics (absorbed)
118
118
 
119
- Loop through all `specs/epics/*.yaml` files and print a summary of story counts per epic. Useful for understanding overall project scope and epic distribution.
119
+ Loop through all `specs/epics/*/epic.yaml` files and print a summary of story counts per epic. Useful for understanding overall project scope and epic distribution.
120
120
 
121
121
  ### check-gates (absorbed)
122
122
 
@@ -1,20 +1,20 @@
1
1
  ---
2
2
  name: trace-requirement
3
3
  model: haiku
4
- description: Link story IDs from specs/release-plan.yaml + epic shards to the implementing code and tests. Produces specs/TRACEABILITY.md. Use when you want to verify coverage of a release plan, audit which stories are implemented, or find "dark" stories with no code.
4
+ description: Link story IDs from specs/release-plan.yaml + epic capsule directories to the implementing code and tests. Produces specs/TRACEABILITY.md. Use when you want to verify coverage of a release plan, audit which stories are implemented, or find "dark" stories with no code.
5
5
  ---
6
6
 
7
7
  # Trace Requirement
8
8
 
9
- Build a traceability matrix from `specs/release-plan.yaml + epic shards` to implementing code and tests. Surfaces gaps in both directions: stories with no code, and code with no story.
9
+ Build a traceability matrix from `specs/release-plan.yaml + epic capsule directories` to implementing code and tests. Surfaces gaps in both directions: stories with no code, and code with no story.
10
10
 
11
11
  ## Pre-flight
12
12
 
13
- > **HARD GATE** — `specs/release-plan.yaml + epic shards` must exist. If it doesn't, run `plan-release` first.
13
+ > **HARD GATE** — `specs/release-plan.yaml + epic capsule directories` must exist. If it doesn't, run `plan-release` first.
14
14
 
15
- → verify: `[ -f specs/release-plan.yaml + epic shards ] && echo "ready" || echo "BLOCKED: run plan-release first"`
15
+ → verify: `[ -f specs/release-plan.yaml + epic capsule directories ] && echo "ready" || echo "BLOCKED: run plan-release first"`
16
16
 
17
- Read `specs/release-plan.yaml + epic shards` fully before proceeding.
17
+ Read `specs/release-plan.yaml + epic capsule directories` fully before proceeding.
18
18
 
19
19
  ## Process
20
20
 
@@ -22,7 +22,7 @@ Read `specs/release-plan.yaml + epic shards` fully before proceeding.
22
22
 
23
23
  From release-plan.yaml, collect all story IDs (e.g. `1.1`, `1.2`, `2.1`).
24
24
 
25
- → verify: `grep -o "Story [0-9]\+\.[0-9]\+" specs/release-plan.yaml + epic shards | sort -u`
25
+ → verify: `grep -o "Story [0-9]\+\.[0-9]\+" specs/release-plan.yaml + epic capsule directories | sort -u`
26
26
 
27
27
  ### 2. Search for story tags in code
28
28
 
@@ -21,7 +21,7 @@ Review answers "is the code good?"; Verify answers "does the built thing do what
21
21
 
22
22
  0. **Branch check** — must not be `main`/`master`.
23
23
 
24
- 1. Read active story tasks and any **Verification Script** notes in `specs/epics/{active}.yaml` or story `.md` under `specs/epics/eNN/stories/`.
24
+ 1. Read active story tasks from `specs/epics/<capsule>/eNNsYY-tasks.yaml` and story spec from `specs/epics/<capsule>/eNNsYY-<slug>.md` (countable-story-format, Gherkin in §17).
25
25
  2. **Cold-start smoke** (if app): stop server, clear caches, boot from scratch.
26
26
  3. Mechanical gates: build → typecheck → lint → tests (from `CLAUDE.md`).
27
27
  4. **Step-by-step UAT** — one user-observable action at a time.
@@ -55,9 +55,42 @@ After UAT, identify and close any gaps between promised behavior and actual beha
55
55
  - Pass: user confirms per step.
56
56
  - Fail: capture expected vs actual; do not mark done in `execution-status.yaml`.
57
57
 
58
+ ## Persist verification evidence
59
+
60
+ After UAT passes, write structured evidence to `specs/verifications/eNNsYY-verify.yaml`:
61
+
62
+ ```yaml
63
+ story_id: e01s01
64
+ verified_at: "2026-06-11T14:30:00Z"
65
+ verifier: verify-work
66
+ phases:
67
+ smoke:
68
+ passed: true
69
+ build:
70
+ passed: true
71
+ command: "npm run build"
72
+ typecheck:
73
+ passed: true
74
+ lint:
75
+ passed: true
76
+ tests:
77
+ passed: true
78
+ coverage: "94.2%"
79
+ manual:
80
+ steps:
81
+ - step: "Open /login"
82
+ expected: "Login form renders"
83
+ actual: "Login form rendered correctly"
84
+ passed: true
85
+ gaps:
86
+ closed: true
87
+ ```
88
+
89
+ > **HARD GATE** — Verification evidence MUST be persisted before marking the story done. No evidence = not verified.
90
+
58
91
  ## Verify
59
92
 
60
- → verify: `grep -c 'verify:' specs/epics/*.yaml | awk '{if($1>0) print "OK"; else print "MISSING"}'`
93
+ → verify: `test -f specs/verifications/<story_id>-verify.yaml && echo "Evidence persisted"`
61
94
 
62
95
  See [REFERENCE.md](REFERENCE.md) for cold-start and gaps template.
63
96
 
@@ -25,7 +25,7 @@ Create high-signal technical documentation that serves as an expert collaborator
25
25
 
26
26
  Choose the correct BMAD-BigPowers artifact:
27
27
  - **Decision Record (ADR)**: For "Why" decisions (saved to `specs/adr/`).
28
- - **Context Map**: For system-wide architectural mapping (`specs/plans/TECH_STACK_LATEST.md`).
28
+ - **Context Map**: For system-wide architectural mapping (`specs/tech-architecture/tech-stack.md`).
29
29
  - **Technical Guide**: For "How-to" with verification (saved to `<module>/REFERENCE.md`).
30
30
  - **Behavioral Feature**: Gherkin-style compliance specs (saved to `specs/audit/features/`).
31
31
  - **Project README**: Project-facing documentation (saved to `README.md` at project root).
@@ -1,32 +0,0 @@
1
- const COLOR_MAP = {
2
- ready: 'green',
3
- blocked: 'red',
4
- in_progress: 'yellow',
5
- done: 'green',
6
- pending: 'dim',
7
- active: 'cyan'
8
- };
9
-
10
- const ICON_MAP = {
11
- ready: '●',
12
- blocked: '✕',
13
- in_progress: '◐',
14
- done: '✓',
15
- pending: '○',
16
- active: '◐'
17
- };
18
-
19
- function gateColor(gateStatus) {
20
- return COLOR_MAP[gateStatus] || 'dim';
21
- }
22
-
23
- function gateIcon(gateStatus) {
24
- return ICON_MAP[gateStatus] || '-';
25
- }
26
-
27
- module.exports = {
28
- gateColor,
29
- gateIcon,
30
- COLOR_MAP,
31
- ICON_MAP
32
- };
@@ -1,89 +0,0 @@
1
- /**
2
- * computeEpicMetrics(cycleTimes)
3
- * Groups cycle times by epic prefix (e.g. e01 from e01s01)
4
- * Returns Map of epicId to { avgCycleMin, totalBcps, avgBcpPerHour }
5
- */
6
- function computeEpicMetrics(cycleTimes) {
7
- if (!cycleTimes || cycleTimes.length === 0) {
8
- return new Map();
9
- }
10
-
11
- const epicMap = new Map();
12
- for (const story of cycleTimes) {
13
- // Extract epic prefix: e01s01 -> e01
14
- const epicId = story.id ? story.id.replace(/s\d+$/, '') : null;
15
- if (!epicId) continue;
16
-
17
- if (!epicMap.has(epicId)) {
18
- epicMap.set(epicId, { stories: [] });
19
- }
20
- epicMap.get(epicId).stories.push(story);
21
- }
22
-
23
- const result = new Map();
24
- for (const [epicId, data] of epicMap) {
25
- const stories = data.stories;
26
- const totalBcps = stories.reduce((sum, s) => sum + (s.bcps || 0), 0);
27
- const totalMin = stories.reduce((sum, s) => sum + (s.cycleMin || 0), 0);
28
- const avgCycleMin = stories.length > 0 ? totalMin / stories.length : 0;
29
- const avgBcpPerHour = totalMin > 0 ? (totalBcps * 60) / totalMin : 0;
30
-
31
- result.set(epicId, {
32
- avgCycleMin,
33
- totalBcps,
34
- avgBcpPerHour
35
- });
36
- }
37
-
38
- return result;
39
- }
40
-
41
- /**
42
- * computeProjectMetrics(cycleTimes)
43
- * Returns { totalBcps, totalMin, avgBcpPerHour } or null if no data
44
- */
45
- function computeProjectMetrics(cycleTimes) {
46
- if (!cycleTimes || cycleTimes.length === 0) {
47
- return null;
48
- }
49
-
50
- const totalBcps = cycleTimes.reduce((sum, s) => sum + (s.bcps || 0), 0);
51
- const totalMin = cycleTimes.reduce((sum, s) => sum + (s.cycleMin || 0), 0);
52
- const avgBcpPerHour = totalMin > 0 ? (totalBcps * 60) / totalMin : 0;
53
-
54
- return {
55
- totalBcps,
56
- totalMin,
57
- avgBcpPerHour
58
- };
59
- }
60
-
61
- /**
62
- * computeCurrentVelocity(cycleTimes, windowStories=3)
63
- * Rolling average of last N stories
64
- * Returns { avgBcpPerHour, avgCycleMin } or null if no data
65
- */
66
- function computeCurrentVelocity(cycleTimes, windowStories = 3) {
67
- if (!cycleTimes || cycleTimes.length === 0) {
68
- return null;
69
- }
70
-
71
- const window = Math.min(windowStories, cycleTimes.length);
72
- const recentStories = cycleTimes.slice(-window);
73
-
74
- const totalBcps = recentStories.reduce((sum, s) => sum + (s.bcps || 0), 0);
75
- const totalMin = recentStories.reduce((sum, s) => sum + (s.cycleMin || 0), 0);
76
- const avgCycleMin = recentStories.length > 0 ? totalMin / recentStories.length : 0;
77
- const avgBcpPerHour = totalMin > 0 ? (totalBcps * 60) / totalMin : 0;
78
-
79
- return {
80
- avgBcpPerHour,
81
- avgCycleMin
82
- };
83
- }
84
-
85
- module.exports = {
86
- computeEpicMetrics,
87
- computeProjectMetrics,
88
- computeCurrentVelocity
89
- };
@@ -1,32 +0,0 @@
1
- const STEPS = [
2
- 'survey-context',
3
- 'plan-work',
4
- 'kickoff-branch',
5
- 'develop-tdd',
6
- 'verify-work',
7
- 'audit-code',
8
- 'commit-message',
9
- 'release-branch'
10
- ];
11
-
12
- function stepIndex(currentStep) {
13
- return STEPS.indexOf(currentStep);
14
- }
15
-
16
- function stepLabel(index) {
17
- if (index < 0 || index >= STEPS.length) {
18
- return '-';
19
- }
20
- return STEPS[index];
21
- }
22
-
23
- function allSteps() {
24
- return [...STEPS];
25
- }
26
-
27
- module.exports = {
28
- stepIndex,
29
- stepLabel,
30
- allSteps,
31
- STEPS
32
- };
@@ -1,122 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const yaml = require('js-yaml');
4
-
5
- /**
6
- * readStateYaml(projectRoot)
7
- * Reads specs/state.yaml and returns an object with mapped fields
8
- * Returns null if file doesn't exist
9
- */
10
- function readStateYaml(projectRoot) {
11
- try {
12
- const filePath = path.join(projectRoot, 'specs', 'state.yaml');
13
- if (!fs.existsSync(filePath)) {
14
- return null;
15
- }
16
- const content = fs.readFileSync(filePath, 'utf8');
17
- const data = yaml.load(content);
18
- return {
19
- activeFlow: data.active_flow || null,
20
- activeEpic: data.active_epic_id || null,
21
- activeStory: data.active_story_id || null,
22
- epicCycle: data.epic_cycle || {},
23
- gitBranch: data.git?.branch || null,
24
- metrics: data.metrics || null,
25
- release: data.release || {},
26
- handoff: data.handoff || {}
27
- };
28
- } catch (err) {
29
- return null;
30
- }
31
- }
32
-
33
- /**
34
- * readExecutionStatus(projectRoot)
35
- * Reads specs/execution-status.yaml and returns { epics: Map }
36
- * Map keys are story/epic IDs, values are status strings
37
- * Returns null if file doesn't exist
38
- */
39
- function readExecutionStatus(projectRoot) {
40
- try {
41
- const filePath = path.join(projectRoot, 'specs', 'execution-status.yaml');
42
- if (!fs.existsSync(filePath)) {
43
- return null;
44
- }
45
- const content = fs.readFileSync(filePath, 'utf8');
46
- const data = yaml.load(content);
47
- const statusMap = new Map();
48
- const devStatus = data.development_status || {};
49
- for (const [key, value] of Object.entries(devStatus)) {
50
- statusMap.set(key, value);
51
- }
52
- return { epics: statusMap };
53
- } catch (err) {
54
- return null;
55
- }
56
- }
57
-
58
- /**
59
- * readEpicShards(projectRoot)
60
- * Reads all files in specs/epics/*.yaml
61
- * Returns array of { id, title, stories } objects or null
62
- */
63
- function readEpicShards(projectRoot) {
64
- try {
65
- const epicsDir = path.join(projectRoot, 'specs', 'epics');
66
- if (!fs.existsSync(epicsDir)) {
67
- return null;
68
- }
69
- const files = fs.readdirSync(epicsDir)
70
- .filter(f => f.endsWith('.yaml'))
71
- .sort();
72
-
73
- const epics = [];
74
- for (const file of files) {
75
- const filePath = path.join(epicsDir, file);
76
- const content = fs.readFileSync(filePath, 'utf8');
77
- const data = yaml.load(content);
78
- epics.push({
79
- id: data.id || null,
80
- title: data.title || null,
81
- stories: data.stories || []
82
- });
83
- }
84
- return epics.length > 0 ? epics : null;
85
- } catch (err) {
86
- return null;
87
- }
88
- }
89
-
90
- /**
91
- * readCycleTimes(projectRoot)
92
- * Reads specs/metrics/cycle-times.yaml stories array
93
- * Returns array of { id, bcps, start, end, cycleMin, bcpPerHour } or null
94
- */
95
- function readCycleTimes(projectRoot) {
96
- try {
97
- const filePath = path.join(projectRoot, 'specs', 'metrics', 'cycle-times.yaml');
98
- if (!fs.existsSync(filePath)) {
99
- return null;
100
- }
101
- const content = fs.readFileSync(filePath, 'utf8');
102
- const data = yaml.load(content);
103
- const stories = data.stories || [];
104
- return stories.map(s => ({
105
- id: s.id || null,
106
- bcps: s.bcps || 0,
107
- start: s.start || null,
108
- end: s.end || null,
109
- cycleMin: s.cycle_min || 0,
110
- bcpPerHour: s.bcp_per_hour || 0
111
- }));
112
- } catch (err) {
113
- return null;
114
- }
115
- }
116
-
117
- module.exports = {
118
- readStateYaml,
119
- readExecutionStatus,
120
- readEpicShards,
121
- readCycleTimes
122
- };