bmad-method 6.8.1-next.2 → 6.8.1-next.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +9 -3
- package/package.json +10 -4
- package/src/bmm-skills/1-analysis/bmad-prfaq/SKILL.md +2 -2
- package/src/bmm-skills/1-analysis/bmad-product-brief/SKILL.md +8 -8
- package/src/bmm-skills/2-plan-workflows/bmad-prd/SKILL.md +7 -7
- package/src/bmm-skills/2-plan-workflows/bmad-prd/assets/headless-schemas.md +2 -2
- package/src/bmm-skills/2-plan-workflows/bmad-prd/customize.toml +1 -1
- package/src/bmm-skills/2-plan-workflows/bmad-prd/references/headless.md +1 -1
- package/src/bmm-skills/2-plan-workflows/bmad-prd/references/validate.md +1 -1
- package/src/bmm-skills/2-plan-workflows/bmad-ux/SKILL.md +8 -8
- package/src/bmm-skills/2-plan-workflows/bmad-ux/assets/design-directions.md +1 -1
- package/src/bmm-skills/2-plan-workflows/bmad-ux/assets/headless-schemas.md +2 -2
- package/src/bmm-skills/2-plan-workflows/bmad-ux/assets/key-screens.md +4 -4
- package/src/bmm-skills/2-plan-workflows/bmad-ux/customize.toml +1 -1
- package/src/bmm-skills/2-plan-workflows/bmad-ux/references/creative-tools.md +1 -1
- package/src/bmm-skills/2-plan-workflows/bmad-ux/references/headless.md +1 -1
- package/src/bmm-skills/2-plan-workflows/bmad-ux/references/validate.md +2 -2
- package/src/bmm-skills/3-solutioning/bmad-agent-architect/customize.toml +2 -2
- package/src/bmm-skills/3-solutioning/bmad-architecture/SKILL.md +85 -0
- package/src/bmm-skills/3-solutioning/bmad-architecture/assets/spine-template.md +79 -0
- package/src/bmm-skills/3-solutioning/bmad-architecture/customize.toml +100 -0
- package/src/bmm-skills/3-solutioning/bmad-architecture/references/headless.md +26 -0
- package/src/bmm-skills/3-solutioning/bmad-architecture/references/reviewer-gate.md +13 -0
- package/src/bmm-skills/3-solutioning/bmad-architecture/scripts/lint_spine.py +257 -0
- package/src/bmm-skills/3-solutioning/bmad-architecture/scripts/tests/test_lint_spine.py +270 -0
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/SKILL.md +16 -60
- package/src/bmm-skills/3-solutioning/bmad-create-epics-and-stories/steps/step-01-validate-prerequisites.md +12 -4
- package/src/bmm-skills/4-implementation/bmad-code-review/steps/step-02-review.md +1 -1
- package/src/bmm-skills/4-implementation/bmad-quick-dev/step-04-review.md +1 -1
- package/src/bmm-skills/4-implementation/bmad-retrospective/SKILL.md +29 -14
- package/src/bmm-skills/4-implementation/bmad-retrospective/customize.toml +1 -1
- package/src/bmm-skills/4-implementation/bmad-sprint-planning/SKILL.md +20 -1
- package/src/bmm-skills/4-implementation/bmad-sprint-planning/checklist.md +2 -1
- package/src/bmm-skills/4-implementation/bmad-sprint-planning/sprint-status-template.yaml +13 -0
- package/src/bmm-skills/4-implementation/bmad-sprint-status/SKILL.md +13 -0
- package/src/bmm-skills/module-help.csv +2 -2
- package/src/core-skills/bmad-brainstorming/SKILL.md +8 -10
- package/src/core-skills/bmad-brainstorming/references/converge.md +1 -1
- package/src/core-skills/bmad-brainstorming/references/finalize.md +1 -1
- package/src/core-skills/bmad-brainstorming/references/headless.md +4 -4
- package/src/core-skills/bmad-brainstorming/references/in-chat-techniques.md +1 -1
- package/src/core-skills/bmad-brainstorming/references/mode-autonomous.md +1 -1
- package/src/core-skills/bmad-brainstorming/scripts/tests/test_brain.py +2 -2
- package/src/core-skills/bmad-customize/scripts/tests/test_list_customizable_skills.py +1 -1
- package/src/core-skills/bmad-forge-idea/SKILL.md +79 -0
- package/src/core-skills/bmad-forge-idea/customize.toml +42 -0
- package/src/core-skills/bmad-forge-idea/scripts/resolve_personas.py +270 -0
- package/src/core-skills/bmad-forge-idea/scripts/tests/test_resolve_personas.py +138 -0
- package/src/core-skills/bmad-party-mode/SKILL.md +39 -56
- package/src/core-skills/bmad-party-mode/customize.toml +175 -0
- package/src/core-skills/bmad-party-mode/references/create-party.md +70 -0
- package/src/core-skills/bmad-party-mode/references/mode-agent-team.md +11 -0
- package/src/core-skills/bmad-party-mode/references/mode-auto.md +13 -0
- package/src/core-skills/bmad-party-mode/references/mode-subagent.md +19 -0
- package/src/core-skills/bmad-party-mode/references/party-memory.md +51 -0
- package/src/core-skills/bmad-party-mode/scripts/resolve_party.py +272 -0
- package/src/core-skills/bmad-party-mode/scripts/tests/test-resolve_party.py +146 -0
- package/src/core-skills/bmad-spec/SKILL.md +25 -9
- package/src/core-skills/bmad-spec/assets/headless-schemas.md +3 -3
- package/src/core-skills/bmad-spec/assets/spec-template.md +4 -4
- package/src/core-skills/module-help.csv +1 -0
- package/src/{core-skills/bmad-brainstorming/scripts → scripts}/memlog.py +56 -34
- package/src/scripts/resolve_config.py +8 -6
- package/src/scripts/resolve_customization.py +8 -6
- package/src/{core-skills/bmad-brainstorming/scripts → scripts}/tests/test_memlog.py +68 -27
- package/tools/installer/commands/install.js +3 -0
- package/tools/installer/core/installer.js +35 -1
- package/tools/installer/core/uv-check.js +97 -0
- package/tools/installer/core/wsl-node-check.js +109 -0
- package/tools/installer/ide/platform-codes.yaml +14 -0
- package/tools/installer/install-messages.yaml +4 -0
- package/tools/installer/ui.js +11 -0
- package/evals/bmm-skills/bmad-product-brief/evals.json +0 -237
- package/evals/bmm-skills/bmad-product-brief/files/branfield-memo.md +0 -46
- package/evals/bmm-skills/bmad-product-brief/files/forkbird-brief/addendum.md +0 -40
- package/evals/bmm-skills/bmad-product-brief/files/forkbird-brief/brief.md +0 -56
- package/evals/bmm-skills/bmad-product-brief/files/forkbird-brief/decision-log.md +0 -27
- package/evals/bmm-skills/bmad-product-brief/files/meridian-mobility-report.md +0 -116
- package/evals/bmm-skills/bmad-product-brief/files/mossridge-brief/addendum.md +0 -41
- package/evals/bmm-skills/bmad-product-brief/files/mossridge-brief/brief.md +0 -57
- package/evals/bmm-skills/bmad-product-brief/files/mossridge-brief/decision-log.md +0 -29
- package/evals/bmm-skills/bmad-product-brief/files/pantry-bridge-interviews.md +0 -90
- package/evals/bmm-skills/bmad-product-brief/files/q2-brainstorm.md +0 -101
- package/evals/bmm-skills/bmad-product-brief/triggers.json +0 -18
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/architecture-decision-template.md +0 -12
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/data/domain-complexity.csv +0 -13
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/data/project-types.csv +0 -7
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-01-init.md +0 -153
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-01b-continue.md +0 -173
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-02-context.md +0 -224
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-03-starter.md +0 -329
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-04-decisions.md +0 -318
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-05-patterns.md +0 -359
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-06-structure.md +0 -379
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-07-validation.md +0 -361
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-08-complete.md +0 -82
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# /// script
|
|
2
|
+
# requires-python = ">=3.10"
|
|
3
|
+
# dependencies = ["pytest>=8.0"]
|
|
4
|
+
# ///
|
|
5
|
+
"""Tests for lint_spine.py. Run: uv run --with pytest pytest scripts/tests/test_lint_spine.py
|
|
6
|
+
|
|
7
|
+
The spine under test: a clean spine lints empty; the linter catches exactly the
|
|
8
|
+
mechanical defects a prompt is unreliable at — literal placeholders, AD-n id breakage,
|
|
9
|
+
AD-n blocks missing required fields, and unpinned Stack versions.
|
|
10
|
+
"""
|
|
11
|
+
import importlib.util
|
|
12
|
+
import json
|
|
13
|
+
import re
|
|
14
|
+
import sys
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
import pytest
|
|
18
|
+
|
|
19
|
+
_SPEC = importlib.util.spec_from_file_location(
|
|
20
|
+
"lint_spine", Path(__file__).resolve().parent.parent / "lint_spine.py"
|
|
21
|
+
)
|
|
22
|
+
lint_spine = importlib.util.module_from_spec(_SPEC)
|
|
23
|
+
sys.modules["lint_spine"] = lint_spine
|
|
24
|
+
_SPEC.loader.exec_module(lint_spine)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
CLEAN = """---
|
|
28
|
+
name: 'Demo'
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Invariants & Rules
|
|
32
|
+
|
|
33
|
+
### AD-1 — single write path
|
|
34
|
+
|
|
35
|
+
- **Binds:** all
|
|
36
|
+
- **Prevents:** divergent mutation
|
|
37
|
+
- **Rule:** state changes only through the command bus
|
|
38
|
+
|
|
39
|
+
### AD-2 — layered deps `[ADOPTED]`
|
|
40
|
+
|
|
41
|
+
- **Binds:** all
|
|
42
|
+
- **Prevents:** import cycles
|
|
43
|
+
- **Rule:** ui -> app -> domain, never backward
|
|
44
|
+
|
|
45
|
+
```mermaid
|
|
46
|
+
flowchart LR
|
|
47
|
+
A --> B{decision}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Stack
|
|
51
|
+
|
|
52
|
+
| Name | Version |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| fastapi | 0.115 |
|
|
55
|
+
| pydantic | 2.9 |
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def cats(result):
|
|
60
|
+
return sorted(f["category"] for f in result["findings"])
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_clean_spine_passes():
|
|
64
|
+
result = lint_spine.lint(CLEAN)
|
|
65
|
+
assert result["ok"] is True
|
|
66
|
+
assert result["total_findings"] == 0
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_mermaid_braces_not_flagged():
|
|
70
|
+
# the {decision} node lives in a fenced block and must not read as a template token
|
|
71
|
+
result = lint_spine.lint(CLEAN)
|
|
72
|
+
assert "placeholder" not in cats(result)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_placeholder_markers_caught():
|
|
76
|
+
text = CLEAN.replace("the command bus", "TBD")
|
|
77
|
+
result = lint_spine.lint(text)
|
|
78
|
+
assert "placeholder" in cats(result)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_similar_to_caught():
|
|
82
|
+
text = CLEAN.replace("import cycles", "similar to AD-1")
|
|
83
|
+
result = lint_spine.lint(text)
|
|
84
|
+
assert any("cross-reference" in f["detail"] for f in result["findings"])
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def test_unfilled_template_token_caught():
|
|
88
|
+
text = CLEAN.replace("single write path", "{decision}")
|
|
89
|
+
result = lint_spine.lint(text)
|
|
90
|
+
assert any(f["category"] == "placeholder" for f in result["findings"])
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def test_duplicate_ad_id_caught():
|
|
94
|
+
text = CLEAN.replace("### AD-2 — layered deps `[ADOPTED]`", "### AD-1 — layered deps")
|
|
95
|
+
result = lint_spine.lint(text)
|
|
96
|
+
assert "ad_id" in cats(result)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def test_non_monotonic_ad_id_caught():
|
|
100
|
+
text = CLEAN.replace("### AD-2 — layered deps `[ADOPTED]`", "### AD-5 — layered deps").replace(
|
|
101
|
+
"### AD-1 — single write path", "### AD-9 — single write path"
|
|
102
|
+
)
|
|
103
|
+
result = lint_spine.lint(text)
|
|
104
|
+
assert any("non-monotonic" in f["detail"] for f in result["findings"])
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def test_missing_field_caught():
|
|
108
|
+
text = CLEAN.replace("- **Rule:** state changes only through the command bus\n", "")
|
|
109
|
+
result = lint_spine.lint(text)
|
|
110
|
+
assert any(f["category"] == "ad_fields" and "rule" in f["detail"] for f in result["findings"])
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_unpinned_dep_caught():
|
|
114
|
+
text = CLEAN.replace("| fastapi | 0.115 |", "| fastapi | |")
|
|
115
|
+
result = lint_spine.lint(text)
|
|
116
|
+
assert "version_pin" in cats(result)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_placeholder_version_caught():
|
|
120
|
+
text = CLEAN.replace("| fastapi | 0.115 |", "| fastapi | {pin} |")
|
|
121
|
+
result = lint_spine.lint(text)
|
|
122
|
+
assert any(f["category"] == "version_pin" and "fastapi" in f["detail"] for f in result["findings"])
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def test_no_stack_section_ok():
|
|
126
|
+
text = CLEAN.split("## Stack")[0]
|
|
127
|
+
result = lint_spine.lint(text)
|
|
128
|
+
assert "version_pin" not in cats(result)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def test_stack_skeleton_row_not_version_pinned():
|
|
132
|
+
# a leftover {token} name is the placeholder pass's job, not a double-reported version_pin
|
|
133
|
+
text = CLEAN.replace("| fastapi | 0.115 |", "| {language / framework} | {pinned version} |")
|
|
134
|
+
result = lint_spine.lint(text)
|
|
135
|
+
assert "version_pin" not in cats(result)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def test_stack_html_comment_not_parsed_as_row():
|
|
139
|
+
text = CLEAN.replace("## Stack\n", "## Stack\n\n<!-- SEED — verified current 2026-06 -->\n")
|
|
140
|
+
result = lint_spine.lint(text)
|
|
141
|
+
assert "version_pin" not in cats(result)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def test_template_token_is_low_severity():
|
|
145
|
+
# a bare {token} can be legitimate brace prose; it is flagged, but low (not high) so the
|
|
146
|
+
# mechanical pass stays near-zero false-positive
|
|
147
|
+
text = CLEAN.replace("single write path", "{decision}")
|
|
148
|
+
result = lint_spine.lint(text)
|
|
149
|
+
toks = [f for f in result["findings"] if f["category"] == "placeholder" and "template token" in f["detail"]]
|
|
150
|
+
assert toks and all(f["severity"] == "low" for f in toks)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def test_no_frontmatter_body_still_scanned():
|
|
154
|
+
text = "## Invariants\n\n### AD-1 — x\n\n- **Binds:** all\n- **Prevents:** drift\n- **Rule:** TBD\n"
|
|
155
|
+
result = lint_spine.lint(text)
|
|
156
|
+
assert "placeholder" in cats(result) # TBD caught even with no frontmatter
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def test_frontmatter_value_with_dashes_not_truncated():
|
|
160
|
+
# a value containing '---' must not be read as the closing fence (line-exact close)
|
|
161
|
+
text = ("---\nname: 'x'\nscope: 'phase 1 --- phase 2'\n---\n\n"
|
|
162
|
+
"## Stack\n\n| Name | Version |\n| --- | --- |\n| fastapi | |\n")
|
|
163
|
+
result = lint_spine.lint(text)
|
|
164
|
+
assert any(f["category"] == "version_pin" for f in result["findings"]) # read past the inline ---
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def test_ad_heading_in_fence_not_counted():
|
|
168
|
+
text = (
|
|
169
|
+
"---\nname: 'x'\n---\n\n"
|
|
170
|
+
"### AD-1 — real\n\n- **Binds:** all\n- **Prevents:** drift\n- **Rule:** do x\n\n"
|
|
171
|
+
"## Docs\n\n```text\n### AD-2 — illustrative only, no fields\n```\n"
|
|
172
|
+
)
|
|
173
|
+
result = lint_spine.lint(text)
|
|
174
|
+
assert result["ok"] is True # the fenced AD-2 is not a live AD → no ad_fields/ad_id finding
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def test_stack_table_flags_only_the_unpinned_row():
|
|
178
|
+
text = ("---\nname: 'x'\n---\n\n## Stack\n\n| Name | Version |\n| --- | --- |\n"
|
|
179
|
+
"| fastapi | 0.115 |\n| redis | |\n")
|
|
180
|
+
result = lint_spine.lint(text)
|
|
181
|
+
pins = [f for f in result["findings"] if f["category"] == "version_pin"]
|
|
182
|
+
assert len(pins) == 1 and "redis" in pins[0]["detail"]
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def test_stack_table_all_pinned_ok():
|
|
186
|
+
text = ("---\nname: 'x'\n---\n\n## Stack\n\n| Name | Version |\n| --- | --- |\n"
|
|
187
|
+
"| fastapi | 0.115 |\n")
|
|
188
|
+
result = lint_spine.lint(text)
|
|
189
|
+
assert "version_pin" not in cats(result)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def test_fenced_stack_rows_not_parsed():
|
|
193
|
+
# an illustrative fenced table under ## Stack must not be read as live rows (fences are
|
|
194
|
+
# blanked first, like every other pass) — a blank-version row inside a fence is not a finding
|
|
195
|
+
text = ("---\nname: 'x'\n---\n\n## Stack\n\n| Name | Version |\n| --- | --- |\n"
|
|
196
|
+
"| fastapi | 0.115 |\n\n```text\n| example | |\n```\n")
|
|
197
|
+
result = lint_spine.lint(text)
|
|
198
|
+
assert "version_pin" not in cats(result)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def test_fenced_stack_heading_not_live():
|
|
202
|
+
# a `## Stack` heading shown inside a code fence is not the live Stack section
|
|
203
|
+
text = ("---\nname: 'x'\n---\n\n## Docs\n\n```md\n## Stack\n\n| foo | |\n```\n")
|
|
204
|
+
result = lint_spine.lint(text)
|
|
205
|
+
assert "version_pin" not in cats(result)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def test_renamed_stack_heading_still_scanned():
|
|
209
|
+
# the heading match is word-boundary, so a varied `## Stack` heading still counts
|
|
210
|
+
text = ("---\nname: 'x'\n---\n\n## Stack & Versions\n\n| Name | Version |\n| --- | --- |\n"
|
|
211
|
+
"| redis | |\n")
|
|
212
|
+
result = lint_spine.lint(text)
|
|
213
|
+
pins = [f for f in result["findings"] if f["category"] == "version_pin"]
|
|
214
|
+
assert len(pins) == 1 and "redis" in pins[0]["detail"]
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def test_reordered_columns_pair_name_to_version():
|
|
218
|
+
# Version-then-Name header: the unpinned row must still be flagged by its real name
|
|
219
|
+
text = ("---\nname: 'x'\n---\n\n## Stack\n\n| Version | Name |\n| --- | --- |\n"
|
|
220
|
+
"| 0.115 | fastapi |\n| | redis |\n")
|
|
221
|
+
result = lint_spine.lint(text)
|
|
222
|
+
pins = [f for f in result["findings"] if f["category"] == "version_pin"]
|
|
223
|
+
assert len(pins) == 1 and "redis" in pins[0]["detail"]
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def test_placeholder_line_number_is_absolute():
|
|
227
|
+
# a TBD after a multi-line fence reports its real file line (fence blanked, not collapsed)
|
|
228
|
+
text = (
|
|
229
|
+
"---\nname: 'x'\n---\n\n"
|
|
230
|
+
"## A\n\n"
|
|
231
|
+
"```text\nf1\nf2\nf3\n```\n\n"
|
|
232
|
+
"TBD here\n"
|
|
233
|
+
)
|
|
234
|
+
result = lint_spine.lint(text)
|
|
235
|
+
ph = next(f for f in result["findings"] if "TBD" in f["detail"])
|
|
236
|
+
n = int(re.search(r"line (\d+)", ph["location"]).group(1))
|
|
237
|
+
assert n == 13
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def test_missing_spine_file_reports_error(tmp_path, capsys):
|
|
241
|
+
rc = lint_spine.main(["--workspace", str(tmp_path)])
|
|
242
|
+
out = json.loads(capsys.readouterr().out)
|
|
243
|
+
assert rc == 0 and out["ok"] is False and "not found" in out["error"]
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def test_frontmatter_unfilled_token_caught():
|
|
247
|
+
# an unfilled {scope}/{paradigm}/{date} in frontmatter is part of the contract and must lint
|
|
248
|
+
text = "---\nname: 'x'\nscope: '{what this spine governs}'\n---\n\n## Invariants\n"
|
|
249
|
+
result = lint_spine.lint(text)
|
|
250
|
+
fm = [f for f in result["findings"] if f["category"] == "placeholder" and "frontmatter" in f["detail"]]
|
|
251
|
+
assert fm and any("template token" in f["detail"] for f in fm)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def test_frontmatter_tbd_caught():
|
|
255
|
+
text = "---\nname: 'x'\nstatus: TBD\n---\n\n## Invariants\n"
|
|
256
|
+
result = lint_spine.lint(text)
|
|
257
|
+
assert any(f["category"] == "placeholder" and "frontmatter" in f["detail"] and "TBD" in f["detail"]
|
|
258
|
+
for f in result["findings"])
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def test_unreadable_spine_returns_error_not_crash(tmp_path, capsys):
|
|
262
|
+
# a spine that exists but can't be UTF-8 decoded must yield error JSON + exit 0, not a traceback
|
|
263
|
+
(tmp_path / lint_spine.SPINE).write_bytes(b"\xff\xfe bad bytes not utf-8")
|
|
264
|
+
rc = lint_spine.main(["--workspace", str(tmp_path)])
|
|
265
|
+
out = json.loads(capsys.readouterr().out)
|
|
266
|
+
assert rc == 0 and out["ok"] is False and "could not read" in out["error"]
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
if __name__ == "__main__":
|
|
270
|
+
sys.exit(pytest.main([__file__, "-q"]))
|
|
@@ -1,74 +1,30 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bmad-create-architecture
|
|
3
|
-
description: '
|
|
3
|
+
description: 'DEPRECATED — consolidated into bmad-architecture create intent - this skill will be removed in v7 in favor of `bmad-architecture`.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# DEPRECATED — forwards to bmad-architecture (create intent)
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
**Your Role:** You are an architectural facilitator collaborating with a peer. This is a partnership, not a client-vendor relationship. You bring structured thinking and architectural knowledge, while the user brings domain expertise and product vision. Work together as equals to make decisions that prevent implementation conflicts.
|
|
11
|
-
|
|
12
|
-
## Conventions
|
|
13
|
-
|
|
14
|
-
- Bare paths (e.g. `steps/step-01-init.md`) resolve from the skill root.
|
|
15
|
-
- `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives).
|
|
16
|
-
- `{project-root}`-prefixed paths resolve from the project working directory.
|
|
17
|
-
- `{skill-name}` resolves to the skill directory's basename.
|
|
18
|
-
|
|
19
|
-
## WORKFLOW ARCHITECTURE
|
|
20
|
-
|
|
21
|
-
This uses **micro-file architecture** for disciplined execution:
|
|
22
|
-
|
|
23
|
-
- Each step is a self-contained file with embedded rules
|
|
24
|
-
- Sequential progression with user control at each step
|
|
25
|
-
- Document state tracked in frontmatter
|
|
26
|
-
- Append-only document building through conversation
|
|
27
|
-
- You NEVER proceed to a step file if the current step file indicates the user must approve and indicate continuation.
|
|
8
|
+
This skill was consolidated into `bmad-architecture`. It is retained as a thin compatibility shim so existing invocations by name and `_bmad/custom/bmad-create-architecture.toml` override files keep working. New work should invoke `bmad-architecture` directly — it detects create / update / validate intent from the conversation.
|
|
28
9
|
|
|
29
10
|
## On Activation
|
|
30
11
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
|
|
34
|
-
|
|
35
|
-
**If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
|
|
36
|
-
|
|
37
|
-
1. `{skill-root}/customize.toml` — defaults
|
|
38
|
-
2. `{project-root}/_bmad/custom/{skill-name}.toml` — team overrides
|
|
39
|
-
3. `{project-root}/_bmad/custom/{skill-name}.user.toml` — personal overrides
|
|
40
|
-
|
|
41
|
-
Any missing file is skipped. Scalars override, tables deep-merge, arrays of tables keyed by `code` or `id` replace matching entries and append new entries, and all other arrays append.
|
|
42
|
-
|
|
43
|
-
### Step 2: Execute Prepend Steps
|
|
44
|
-
|
|
45
|
-
Execute each entry in `{workflow.activation_steps_prepend}` in order before proceeding.
|
|
46
|
-
|
|
47
|
-
### Step 3: Load Persistent Facts
|
|
48
|
-
|
|
49
|
-
Treat every entry in `{workflow.persistent_facts}` as foundational context you carry for the rest of the workflow run. Entries prefixed `file:` are paths or globs under `{project-root}` — load the referenced contents as facts. All other entries are facts verbatim.
|
|
50
|
-
|
|
51
|
-
### Step 4: Load Config
|
|
52
|
-
|
|
53
|
-
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
|
|
54
|
-
- Use `{user_name}` for greeting
|
|
55
|
-
- Use `{communication_language}` for all communications
|
|
56
|
-
- Use `{document_output_language}` for output documents
|
|
57
|
-
- Use `{planning_artifacts}` for output location and artifact scanning
|
|
58
|
-
- Use `{project_knowledge}` for additional context scanning
|
|
59
|
-
|
|
60
|
-
### Step 5: Greet the User
|
|
61
|
-
|
|
62
|
-
Greet `{user_name}`, speaking in `{communication_language}`.
|
|
12
|
+
1. Resolve customization: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-create-architecture.toml` and `bmad-create-architecture.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
|
|
63
13
|
|
|
64
|
-
|
|
14
|
+
2. Load `{project-root}/_bmad/bmm/config.yaml` (and `config.user.yaml` if present) to resolve `{user_name}` and `{communication_language}`.
|
|
65
15
|
|
|
66
|
-
|
|
16
|
+
3. Emit a deprecation notice to the user in `{communication_language}`:
|
|
67
17
|
|
|
68
|
-
|
|
18
|
+
> Notice: `bmad-create-architecture` is deprecated and will be removed in a future release. It now forwards to `bmad-architecture` with create intent. To silence this notice and access the full new customization surface (`spine_template`, `spine_output_path`, `run_folder_pattern`, `doc_standards`, `external_sources`, `external_handoffs`, `finalize_reviewers`), migrate `_bmad/custom/bmad-create-architecture.toml` to `_bmad/custom/bmad-architecture.toml` and invoke `bmad-architecture` directly next time. Customization fields that were in this version still remain in the new version and will be respected if present in `_bmad/custom/bmad-architecture.toml`, but the new version also supports additional fields that you can take advantage of by migrating.
|
|
69
19
|
|
|
70
|
-
|
|
20
|
+
4. Invoke `bmad-architecture` with the following context. Pass these as the activating context so `bmad-architecture` honors them instead of resolving its own customization from scratch:
|
|
71
21
|
|
|
72
|
-
|
|
22
|
+
- **Intent:** `create` — skip `bmad-architecture`'s usual intent detection step.
|
|
23
|
+
- **Pre-resolved legacy customization** — use these in place of resolving from `bmad-architecture`'s own `customize.toml` for the four legacy fields. For everything else (`spine_template`, `spine_output_path`, `run_folder_pattern`, `doc_standards`, `external_sources`, `external_handoffs`, `finalize_reviewers`), use `bmad-architecture`'s own defaults and overrides as normal:
|
|
24
|
+
- `activation_steps_prepend` = the resolved value from step 1
|
|
25
|
+
- `activation_steps_append` = the resolved value from step 1
|
|
26
|
+
- `persistent_facts` = the resolved value from step 1
|
|
27
|
+
- `on_complete` = the resolved value from step 1
|
|
28
|
+
- **Original user input:** forward whatever the user said when invoking this skill verbatim.
|
|
73
29
|
|
|
74
|
-
|
|
30
|
+
`bmad-architecture` takes the workflow from here. Do not execute any further steps in this shim.
|
|
@@ -48,7 +48,7 @@ Verify required documents exist and are complete:
|
|
|
48
48
|
|
|
49
49
|
1. **PRD.md** - Contains requirements (FRs and NFRs) and product scope
|
|
50
50
|
2. **Architecture.md** - Contains technical decisions, API contracts, data models
|
|
51
|
-
3. **UX
|
|
51
|
+
3. **UX design contract** (if UI exists) - Contains visual identity, interaction patterns, mockups, and user flows
|
|
52
52
|
|
|
53
53
|
### 2. Document Discovery and Validation
|
|
54
54
|
|
|
@@ -66,8 +66,16 @@ Search for required documents using these patterns (sharded means a large docume
|
|
|
66
66
|
|
|
67
67
|
**UX Design Document Search (Optional):**
|
|
68
68
|
|
|
69
|
-
1. `{planning_artifacts}
|
|
70
|
-
2. `{planning_artifacts}/*ux
|
|
69
|
+
1. `{planning_artifacts}/ux-designs/ux-*/DESIGN.md` and `{planning_artifacts}/ux-designs/ux-*/EXPERIENCE.md` (bmad-ux spine pair)
|
|
70
|
+
2. `{planning_artifacts}/*ux*.md` (legacy whole document)
|
|
71
|
+
3. `{planning_artifacts}/*ux*/index.md` (legacy sharded version)
|
|
72
|
+
|
|
73
|
+
For each matching bmad-ux run folder, treat `DESIGN.md` and `EXPERIENCE.md` as one UX design contract:
|
|
74
|
+
|
|
75
|
+
- Confirm and load both files together. `DESIGN.md` owns visual identity and design tokens; `EXPERIENCE.md` owns information architecture, behavior, states, interactions, accessibility, and journeys.
|
|
76
|
+
- Add both files to the `inputDocuments: []` frontmatter array.
|
|
77
|
+
- If only one spine exists, report the incomplete pair and ask whether the user wants to include the partial UX handoff.
|
|
78
|
+
- If multiple run folders match, show each run folder with the spine frontmatter `status` and `updated` values when available, then ask the user which UX design contract to include.
|
|
71
79
|
|
|
72
80
|
Before proceeding, Ask the user if there are any other documents to include for analysis, and if anything found should be excluded. Wait for user confirmation. Once confirmed, create the {planning_artifacts}/epics.md from the ../templates/epics-template.md and in the front matter list the files in the array of `inputDocuments: []`.
|
|
73
81
|
|
|
@@ -136,7 +144,7 @@ Review the Architecture document for technical requirements that impact epic and
|
|
|
136
144
|
|
|
137
145
|
**IMPORTANT**: The UX Design Specification is a first-class input document, not supplementary material. Requirements from the UX spec must be extracted with the same rigor as PRD functional requirements.
|
|
138
146
|
|
|
139
|
-
Read the FULL UX
|
|
147
|
+
Read the FULL UX design contract and extract ALL actionable work items. For a bmad-ux spine pair, read both `DESIGN.md` and `EXPERIENCE.md`:
|
|
140
148
|
|
|
141
149
|
**Look for:**
|
|
142
150
|
|
|
@@ -18,7 +18,7 @@ failed_layers: '' # set at runtime: comma-separated list of layers that failed o
|
|
|
18
18
|
|
|
19
19
|
2. Launch parallel subagents without conversation context. If subagents are not available, generate prompt files in `{implementation_artifacts}` — one per reviewer role below — and HALT. Ask the user to run each in a separate session (ideally a different LLM) and paste back the findings. When findings are pasted, resume from this point and proceed to step 3.
|
|
20
20
|
|
|
21
|
-
- **Blind Hunter** — receives `{diff_output}` only. No spec, no context docs, no project access. Invoke via the `bmad-review-adversarial-general` skill.
|
|
21
|
+
- **Blind Hunter** — receives inline `{diff_output}` only. No spec, no context docs, no project access. Invoke via the `bmad-review-adversarial-general` skill.
|
|
22
22
|
|
|
23
23
|
- **Edge Case Hunter** — receives `{diff_output}` and read access to the project. Invoke via the `bmad-review-edge-case-hunter` skill.
|
|
24
24
|
|
|
@@ -25,7 +25,7 @@ Do NOT `git add` anything — this is read-only inspection.
|
|
|
25
25
|
|
|
26
26
|
Launch three subagents without conversation context. If no sub-agents are available, generate three review prompt files in `{implementation_artifacts}` — one per reviewer role below — and HALT. Ask the human to run each in a separate session (ideally a different LLM) and paste back the findings.
|
|
27
27
|
|
|
28
|
-
- **Blind hunter** — receives `{diff_output}` only. No spec, no context docs, no project access. Invoke via the `bmad-review-adversarial-general` skill.
|
|
28
|
+
- **Blind hunter** — receives inline `{diff_output}` only. No spec, no context docs, no project access. Invoke via the `bmad-review-adversarial-general` skill.
|
|
29
29
|
- **Edge case hunter** — receives `{diff_output}` and read access to the project. Invoke via the `bmad-review-edge-case-hunter` skill.
|
|
30
30
|
- **Acceptance auditor** — receives `{diff_output}`, `{spec_file}`, and read access to the project. Must also read the docs listed in `{spec_file}` frontmatter `context`. Checks for violations of acceptance criteria, rules, and principles from the spec and context docs.
|
|
31
31
|
|
|
@@ -225,12 +225,12 @@ Amelia (Developer): "Perfect. Epic {{epic_number}} is complete and ready for ret
|
|
|
225
225
|
|
|
226
226
|
</step>
|
|
227
227
|
|
|
228
|
-
<step n="
|
|
228
|
+
<step n="2" goal="Discover and load project documents">
|
|
229
229
|
<action>Load input files according to the Input Files table above. For SELECTIVE_LOAD inputs, load only the epic matching {{epic_number}}. For FULL_LOAD inputs, load the complete document. For INDEX_GUIDED inputs, check the index first and load relevant sections. After discovery, these content variables are available: {epics_content} (selective load for this epic), {architecture_content}, {prd_content}, {document_project_content}</action>
|
|
230
230
|
<note>After discovery, these content variables are available: {epics_content} (selective load for this epic), {architecture_content}, {prd_content}, {document_project_content}</note>
|
|
231
231
|
</step>
|
|
232
232
|
|
|
233
|
-
<step n="
|
|
233
|
+
<step n="3" goal="Deep Story Analysis - Extract Lessons from Implementation">
|
|
234
234
|
|
|
235
235
|
<output>
|
|
236
236
|
Amelia (Developer): "Before we start the team discussion, let me review all the story records to surface key themes. This'll help us have a richer conversation."
|
|
@@ -324,7 +324,7 @@ Amelia (Developer): "We'll get to all of it. But first, let me load the previous
|
|
|
324
324
|
|
|
325
325
|
</step>
|
|
326
326
|
|
|
327
|
-
<step n="
|
|
327
|
+
<step n="4" goal="Load and Integrate Previous Epic Retrospective">
|
|
328
328
|
|
|
329
329
|
<action>Calculate previous epic number: {{prev_epic_num}} = {{epic_number}} - 1</action>
|
|
330
330
|
|
|
@@ -350,6 +350,7 @@ Amelia (Developer): "I found our retrospectives from Epic {{prev_epic_num}}. Let
|
|
|
350
350
|
|
|
351
351
|
**Action Item Follow-Through:**
|
|
352
352
|
- For each action item from Epic {{prev_epic_num}} retro, check if it was completed
|
|
353
|
+
- Cross-check the action_items section in {sprint_status_file} (if present) for Epic {{prev_epic_num}} entries and their current status
|
|
353
354
|
- Look for evidence in current epic's story records
|
|
354
355
|
- Mark each action item: ✅ Completed, ⏳ In Progress, ❌ Not Addressed
|
|
355
356
|
|
|
@@ -420,7 +421,7 @@ Charlie (Senior Dev): "First epic, first retro. Let's make it count."
|
|
|
420
421
|
|
|
421
422
|
</step>
|
|
422
423
|
|
|
423
|
-
<step n="
|
|
424
|
+
<step n="5" goal="Preview Next Epic with Change Detection">
|
|
424
425
|
|
|
425
426
|
<action>Calculate next epic number: {{next_epic_num}} = {{epic_number}} + 1</action>
|
|
426
427
|
|
|
@@ -509,7 +510,7 @@ Amelia (Developer): "No problem. We'll still do a thorough retro on Epic {{epic_
|
|
|
509
510
|
|
|
510
511
|
</step>
|
|
511
512
|
|
|
512
|
-
<step n="
|
|
513
|
+
<step n="6" goal="Initialize Retrospective with Rich Context">
|
|
513
514
|
|
|
514
515
|
<action>Load agent roster from {agent_roster}</action>
|
|
515
516
|
<action>Identify which agents participated in Epic {{epic_number}} based on story records</action>
|
|
@@ -599,7 +600,7 @@ Amelia (Developer): "Exactly. {user_name}, any questions before we dive in?"
|
|
|
599
600
|
|
|
600
601
|
</step>
|
|
601
602
|
|
|
602
|
-
<step n="
|
|
603
|
+
<step n="7" goal="Epic Review Discussion - What Went Well, What Didn't">
|
|
603
604
|
|
|
604
605
|
<output>
|
|
605
606
|
Amelia (Developer): "Let's start with the good stuff. What went well in Epic {{epic_number}}?"
|
|
@@ -673,7 +674,7 @@ Alice (Product Owner): "I appreciate that. I could've been more proactive about
|
|
|
673
674
|
Amelia (Developer): "This is good. We're identifying systemic improvements, not assigning blame."
|
|
674
675
|
</output>
|
|
675
676
|
|
|
676
|
-
<action>Continue the discussion, weaving in patterns discovered from the deep story analysis (Step
|
|
677
|
+
<action>Continue the discussion, weaving in patterns discovered from the deep story analysis (Step 3)</action>
|
|
677
678
|
|
|
678
679
|
<output>
|
|
679
680
|
Amelia (Developer): "Speaking of patterns, I noticed something when reviewing all the story records..."
|
|
@@ -744,13 +745,13 @@ Amelia (Developer): "Does that capture it? Anyone have something important we mi
|
|
|
744
745
|
|
|
745
746
|
</step>
|
|
746
747
|
|
|
747
|
-
<step n="
|
|
748
|
+
<step n="8" goal="Next Epic Preparation Discussion - Interactive and Collaborative">
|
|
748
749
|
|
|
749
750
|
<check if="{{next_epic_exists}} == false">
|
|
750
751
|
<output>
|
|
751
752
|
Amelia (Developer): "Normally we'd discuss preparing for the next epic, but since Epic {{next_epic_num}} isn't defined yet, let's skip to action items."
|
|
752
753
|
</output>
|
|
753
|
-
<action>Skip to Step
|
|
754
|
+
<action>Skip to Step 9</action>
|
|
754
755
|
</check>
|
|
755
756
|
|
|
756
757
|
<output>
|
|
@@ -868,7 +869,7 @@ Amelia (Developer): "{user_name}, does this preparation plan work for you?"
|
|
|
868
869
|
|
|
869
870
|
</step>
|
|
870
871
|
|
|
871
|
-
<step n="
|
|
872
|
+
<step n="9" goal="Synthesize Action Items with Significant Change Detection">
|
|
872
873
|
|
|
873
874
|
<output>
|
|
874
875
|
Amelia (Developer): "Let's capture concrete action items from everything we've discussed."
|
|
@@ -1109,7 +1110,7 @@ Amelia (Developer): "Everyone clear on what they own?"
|
|
|
1109
1110
|
|
|
1110
1111
|
</step>
|
|
1111
1112
|
|
|
1112
|
-
<step n="
|
|
1113
|
+
<step n="10" goal="Critical Readiness Exploration - Interactive Deep Dive">
|
|
1113
1114
|
|
|
1114
1115
|
<output>
|
|
1115
1116
|
Amelia (Developer): "Before we close, I want to do a final readiness check."
|
|
@@ -1292,7 +1293,7 @@ Charlie (Senior Dev): "Better to catch this now than three stories into the next
|
|
|
1292
1293
|
|
|
1293
1294
|
</step>
|
|
1294
1295
|
|
|
1295
|
-
<step n="
|
|
1296
|
+
<step n="11" goal="Retrospective Closure with Celebration and Commitment">
|
|
1296
1297
|
|
|
1297
1298
|
<output>
|
|
1298
1299
|
Amelia (Developer): "We've covered a lot of ground today. Let me bring this retrospective to a close."
|
|
@@ -1368,7 +1369,7 @@ Amelia (Developer): "See you all when prep work is done. Meeting adjourned!"
|
|
|
1368
1369
|
|
|
1369
1370
|
</step>
|
|
1370
1371
|
|
|
1371
|
-
<step n="
|
|
1372
|
+
<step n="12" goal="Save Retrospective and Update Sprint Status">
|
|
1372
1373
|
|
|
1373
1374
|
<action>Ensure retrospectives folder exists: {implementation_artifacts}</action>
|
|
1374
1375
|
<action>Create folder if it doesn't exist</action>
|
|
@@ -1403,6 +1404,19 @@ Amelia (Developer): "See you all when prep work is done. Meeting adjourned!"
|
|
|
1403
1404
|
<action>Find development_status key "epic-{{epic_number}}-retrospective"</action>
|
|
1404
1405
|
<action>Verify current status (typically "optional" or "pending")</action>
|
|
1405
1406
|
<action>Update development_status["epic-{{epic_number}}-retrospective"] = "done"</action>
|
|
1407
|
+
<action>Append each Epic {{epic_number}} action item to the action_items section, creating the section after development_status if missing. One entry per item:</action>
|
|
1408
|
+
|
|
1409
|
+
```yaml
|
|
1410
|
+
action_items:
|
|
1411
|
+
- epic: {{epic_number}}
|
|
1412
|
+
action: "{{action_description}}"
|
|
1413
|
+
owner: "{{owner}}"
|
|
1414
|
+
status: open
|
|
1415
|
+
```
|
|
1416
|
+
|
|
1417
|
+
<action>Quote action and owner values so punctuation (e.g., "#") cannot break YAML parsing</action>
|
|
1418
|
+
|
|
1419
|
+
<action>Update Epic {{prev_epic_num}} action_items entries based on Step 4 follow-through: ✅ Completed → done, ⏳ In Progress → in-progress, ❌ Not Addressed → keep existing status (do not modify)</action>
|
|
1406
1420
|
<action>Update last_updated field to current date</action>
|
|
1407
1421
|
<action>Save file, preserving ALL comments and structure including STATUS DEFINITIONS</action>
|
|
1408
1422
|
|
|
@@ -1412,6 +1426,7 @@ Amelia (Developer): "See you all when prep work is done. Meeting adjourned!"
|
|
|
1412
1426
|
|
|
1413
1427
|
Retrospective key: epic-{{epic_number}}-retrospective
|
|
1414
1428
|
Status: {{previous_status}} → done
|
|
1429
|
+
Action items recorded: {{action_count}}
|
|
1415
1430
|
</output>
|
|
1416
1431
|
</check>
|
|
1417
1432
|
|
|
@@ -1425,7 +1440,7 @@ Retrospective document was saved successfully, but {sprint_status_file} may need
|
|
|
1425
1440
|
|
|
1426
1441
|
</step>
|
|
1427
1442
|
|
|
1428
|
-
<step n="
|
|
1443
|
+
<step n="13" goal="Final Summary and Handoff">
|
|
1429
1444
|
|
|
1430
1445
|
<output>
|
|
1431
1446
|
**✅ Retrospective Complete, {user_name}!**
|
|
@@ -34,7 +34,7 @@ persistent_facts = [
|
|
|
34
34
|
"file:{project-root}/**/project-context.md",
|
|
35
35
|
]
|
|
36
36
|
|
|
37
|
-
# Scalar: executed when the workflow reaches Step
|
|
37
|
+
# Scalar: executed when the workflow reaches Step 13 (Final Summary and Handoff),
|
|
38
38
|
# after the retrospective document is saved and sprint-status is updated. Override wins.
|
|
39
39
|
# Leave empty for no custom post-completion behavior.
|
|
40
40
|
|
|
@@ -151,6 +151,7 @@ development_status:
|
|
|
151
151
|
|
|
152
152
|
- If existing `{status_file}` exists and has more advanced status, preserve it
|
|
153
153
|
- Never downgrade status (e.g., don't change `done` to `ready-for-dev`)
|
|
154
|
+
- If existing `{status_file}` has an `action_items` section, carry it over unchanged
|
|
154
155
|
|
|
155
156
|
**Status Flow Reference:**
|
|
156
157
|
|
|
@@ -194,12 +195,18 @@ development_status:
|
|
|
194
195
|
# - optional: Can be completed but not required
|
|
195
196
|
# - done: Retrospective has been completed
|
|
196
197
|
#
|
|
198
|
+
# Action Item Status:
|
|
199
|
+
# - open: Committed during a retrospective, not yet addressed
|
|
200
|
+
# - in-progress: Actively being worked on
|
|
201
|
+
# - done: Completed
|
|
202
|
+
#
|
|
197
203
|
# WORKFLOW NOTES:
|
|
198
204
|
# ===============
|
|
199
205
|
# - Epic transitions to 'in-progress' automatically when first story is created
|
|
200
206
|
# - Stories can be worked in parallel if team capacity allows
|
|
201
207
|
# - Developer typically creates next story after previous one is 'done' to incorporate learnings
|
|
202
208
|
# - Dev moves story to 'review', then runs code-review (fresh context, different LLM recommended)
|
|
209
|
+
# - Retrospective appends its action items to action_items; sprint-status surfaces open ones
|
|
203
210
|
|
|
204
211
|
generated: { date }
|
|
205
212
|
last_updated: { date }
|
|
@@ -215,6 +222,7 @@ development_status:
|
|
|
215
222
|
<action>Write the complete sprint status YAML to {status_file}</action>
|
|
216
223
|
<action>CRITICAL: Metadata appears TWICE - once as comments (#) for documentation, once as YAML key:value fields for parsing</action>
|
|
217
224
|
<action>Ensure all items are ordered: epic, its stories, its retrospective, next epic...</action>
|
|
225
|
+
<action>If the existing file had an action_items section, write it back unchanged after development_status</action>
|
|
218
226
|
</step>
|
|
219
227
|
|
|
220
228
|
<step n="5" goal="Validate and report">
|
|
@@ -223,7 +231,8 @@ development_status:
|
|
|
223
231
|
- [ ] Every epic in epic files appears in {status_file}
|
|
224
232
|
- [ ] Every story in epic files appears in {status_file}
|
|
225
233
|
- [ ] Every epic has a corresponding retrospective entry
|
|
226
|
-
- [ ] No items in {status_file} that don't exist in epic files
|
|
234
|
+
- [ ] No development_status items in {status_file} that don't exist in epic files
|
|
235
|
+
- [ ] action_items section (if it existed) carried over unchanged
|
|
227
236
|
- [ ] All status values are legal (match state machine definitions)
|
|
228
237
|
- [ ] File is valid YAML syntax
|
|
229
238
|
|
|
@@ -291,6 +300,16 @@ optional ↔ done
|
|
|
291
300
|
- **optional**: Ready to be conducted but not required
|
|
292
301
|
- **done**: Finished
|
|
293
302
|
|
|
303
|
+
**Action Item Status:**
|
|
304
|
+
|
|
305
|
+
```
|
|
306
|
+
open → in-progress → done
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
- **open**: Committed during a retrospective, not yet addressed
|
|
310
|
+
- **in-progress**: Actively being worked on
|
|
311
|
+
- **done**: Completed
|
|
312
|
+
|
|
294
313
|
### Guidelines
|
|
295
314
|
|
|
296
315
|
1. **Epic Activation**: Mark epic as `in-progress` when starting work on its first story
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
- [ ] Every epic found in epic\*.md files appears in sprint-status.yaml
|
|
8
8
|
- [ ] Every story found in epic\*.md files appears in sprint-status.yaml
|
|
9
9
|
- [ ] Every epic has a corresponding retrospective entry
|
|
10
|
-
- [ ] No items in sprint-status.yaml that don't exist in epic files
|
|
10
|
+
- [ ] No development_status items in sprint-status.yaml that don't exist in epic files
|
|
11
|
+
- [ ] action_items section (if it existed) carried over unchanged
|
|
11
12
|
|
|
12
13
|
### Parsing Verification
|
|
13
14
|
|