Skip to content

Commit c20d65f

Browse files
authored
docs(workflow): sync workflow.md with current feature lifecycle (#64)
1 parent c738888 commit c20d65f

File tree

1 file changed

+100
-14
lines changed

1 file changed

+100
-14
lines changed

docs/workflow.md

Lines changed: 100 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,25 @@ Each step has a designated agent and a specific deliverable. No step is skipped.
3535
│ │
3636
│ Phase 1 — Project Discovery (once per project) │
3737
│ PO asks stakeholder 7 questions → silent pre-mortem │
38-
│ → baseline → create backlog/<name>.feature stubs │
38+
│ → paraphrase + clarify + summarize → stakeholder confirms │
39+
│ → baseline docs/features/discovery.md │
40+
│ → create backlog/<name>.feature stubs (discovery section only) │
3941
│ │
4042
│ Phase 2 — Feature Discovery (per feature) │
41-
│ PO populates Entities table → generates questions from gaps │
42-
│ → interview rounds → stakeholder says "baseline" │
43+
│ PO populates Entities table in .feature file description │
44+
│ → generates questions from gaps, ambiguities, boundaries │
45+
│ → interview rounds → after each round: │
46+
│ paraphrase + clarify + summarize → stakeholder confirms │
47+
│ → stakeholder says "baseline" to freeze discovery │
4348
│ → decomposition check (>2 concerns or >8 examples → split) │
49+
│ → Status: BASELINED written into .feature file description │
4450
│ │
4551
│ Phase 3 — Stories (PO alone) │
4652
│ Write Rule: blocks with user story headers (no Examples yet) │
4753
│ commit: feat(stories): write user stories for <name> │
4854
│ │
4955
│ Phase 4 — Criteria (PO alone) │
56+
│ Silent pre-mortem per Rule │
5057
│ Write @id-tagged Example: blocks under each Rule: │
5158
│ commit: feat(criteria): write acceptance criteria for <name> │
5259
│ ★ FROZEN — changes require @deprecated + new Example │
@@ -58,11 +65,14 @@ Each step has a designated agent and a specific deliverable. No step is skipped.
5865
├─────────────────────────────────────────────────────────────────────┤
5966
│ │
6067
│ mv backlog/<name>.feature → in-progress/<name>.feature │
61-
│ Read discovery + feature file │
68+
│ Read docs/features/discovery.md (project-level) │
69+
│ Read ALL backlog .feature files (discovery + entities sections) │
70+
│ Read in-progress .feature file (full) │
71+
│ Identify cross-feature entities, shared interfaces, extension pts │
6272
│ Silent pre-mortem (YAGNI/KISS/DRY/SOLID/OC/patterns) │
63-
│ Append Architecture section to feature file description
73+
│ Append Architecture section to in-progress .feature description │
6474
│ (Module Structure + ADRs + Build Changes) │
65-
│ Architecture contradiction check → PO acknowledges
75+
│ Architecture contradiction check — resolve with PO if needed
6676
│ commit: feat(<name>): add architecture │
6777
│ │
6878
└─────────────────────────────────────────────────────────────────────┘
@@ -94,13 +104,17 @@ Each step has a designated agent and a specific deliverable. No step is skipped.
94104
│ ↓ │
95105
│ next test │
96106
│ │
97-
│ RED: confirm test fails
107+
│ RED: confirm test fails │
98108
│ GREEN: minimum code to pass (YAGNI + KISS only) │
99109
│ REFACTOR: DRY → SOLID → Object Calisthenics (9 rules) │
100110
│ → type hints → docstrings │
101111
│ SELF-DECLARE: write ## Self-Declaration block in TODO.md │
102-
│ 21-item checklist with file:line evidence │
112+
│ 21-item checklist (YAGNI×2, KISS×2, DRY×2, │
113+
│ SOLID×5, OC×9, Semantic×1) with file:line evidence │
114+
│ each item: checked box + evidence, or N/A + reason │
103115
│ REVIEWER: code-design check only (no lint/pyright/coverage) │
116+
│ reviewer independently verifies YES claims │
117+
│ reviewer does NOT re-audit self-declared failures │
104118
│ COMMIT: feat(<name>): implement <what> │
105119
│ │
106120
│ After all tests green: │
@@ -142,7 +156,7 @@ Each step has a designated agent and a specific deliverable. No step is skipped.
142156
│ │
143157
│ ACCEPTED: │
144158
│ mv in-progress/<name>.feature → completed/<name>.feature │
145-
│ developer creates PR + tags release
159+
│ developer creates PR (squash merge) + tags release │
146160
│ │
147161
│ REJECTED: │
148162
│ feedback in TODO.md → back to relevant step │
@@ -152,13 +166,64 @@ Each step has a designated agent and a specific deliverable. No step is skipped.
152166

153167
---
154168

169+
## Feature File Structure
170+
171+
Each feature is a single `.feature` file. The free-form description before the first `Rule:` contains all discovery content added progressively through the workflow:
172+
173+
```
174+
Feature: <title>
175+
176+
Discovery:
177+
178+
Status: BASELINED (YYYY-MM-DD)
179+
180+
Entities:
181+
| Type | Name | Candidate Class/Method | In Scope |
182+
183+
Rules (Business):
184+
- <business rule>
185+
186+
Constraints:
187+
- <non-functional requirement>
188+
189+
Questions:
190+
| ID | Question | Answer | Status |
191+
192+
Architecture: ← added at Step 2 by developer
193+
194+
### Module Structure
195+
- <package>/domain/entity.py — ...
196+
197+
### Key Decisions
198+
ADR-001: <title>
199+
Decision: <what>
200+
Reason: <why>
201+
202+
Rule: <story title>
203+
As a <role>
204+
I want <goal>
205+
So that <benefit>
206+
207+
@id:a3f2b1c4
208+
Example: <scenario>
209+
Given <context>
210+
When <action>
211+
Then <observable outcome>
212+
```
213+
214+
Two discovery sources:
215+
- `docs/features/discovery.md` — project-level (Who/What/Why/When, once per project)
216+
- Feature file description — per-feature discovery, entities, questions, architecture
217+
218+
---
219+
155220
## Supporting Tools
156221

157222
| Command | When | Purpose |
158223
|---|---|---|
159224
| `uv run task gen-tests` | Step 3, Step 4 | Reads `.feature` files → creates/syncs test stubs in `tests/features/` |
160225
| `uv run task gen-tests -- --check` | Before gen-tests | Dry run — preview what would change |
161-
| `uv run task gen-tests -- --orphans` | Step 5 | List tests with no matching `@id` |
226+
| `uv run task gen-tests -- --orphans` | Step 5 | List tests with no matching `@id` — already validated by gen-tests |
162227
| `uv run task gen-todo` | Every session | Reads in-progress `.feature` → syncs `TODO.md` |
163228
| `uv run task gen-id` | Step 1 Phase 4 | Generate 8-char hex `@id` for a new Example |
164229
| `uv run task test-fast` | Step 4 cycle | Fast test run (no coverage) — used during Red-Green-Refactor |
@@ -183,21 +248,41 @@ tests/
183248

184249
---
185250

186-
## TODO.md Structure (Step 4)
251+
## TODO.md Structure
187252

188253
```markdown
189254
# Current Work
190255

191256
Feature: <name>
192-
Step: 4 (implement)
257+
Step: <1-6> (<step name>)
193258
Source: docs/features/in-progress/<name>.feature
194259

195260
## Cycle State
196261
Test: @id:<hex> — <description>
197262
Phase: RED | GREEN | REFACTOR | SELF-DECLARE | REVIEWER(code-design) | COMMITTED
198263

199264
## Self-Declaration (@id:<hex>)
200-
- [x] YAGNI-1 … SOLID-D … OC-1…OC-9 … Semantic (21 items, file:line each)
265+
- [x] YAGNI-1: No abstractions beyond current AC — `file:line`
266+
- [x] YAGNI-2: No speculative parameters or flags — `file:line`
267+
- [x] KISS-1: Every function has one job — `file:line`
268+
- [x] KISS-2: No unnecessary indirection — `file:line`
269+
- [x] DRY-1: No duplicated logic — `file:line`
270+
- [x] DRY-2: Every shared concept in one place — `file:line`
271+
- [x] SOLID-S: One reason to change — `file:line`
272+
- [x] SOLID-O: Extension, not modification — `file:line` or N/A
273+
- [x] SOLID-L: Subtypes fully substitutable — `file:line` or N/A
274+
- [x] SOLID-I: No forced stub methods — `file:line` or N/A
275+
- [x] SOLID-D: Domain depends on Protocols — `file:line`
276+
- [x] OC-1: One indent level per method — `file:line`
277+
- [x] OC-2: No else after return — `file:line` or N/A
278+
- [x] OC-3: No bare primitives as domain concepts — `file:line` or N/A
279+
- [x] OC-4: No bare collections as domain values — `file:line` or N/A
280+
- [x] OC-5: No chained dot navigation — `file:line` or N/A
281+
- [x] OC-6: No abbreviations — `file:line` or N/A
282+
- [x] OC-7: Functions ≤ 20 lines, classes ≤ 50 lines — `file:line`
283+
- [x] OC-8: ≤ 2 instance variables per class — `file:line`
284+
- [x] OC-9: No getters/setters — `file:line` or N/A
285+
- [x] Semantic: test abstraction matches AC level — `file:line`
201286

202287
## Progress
203288
- [x] @id:<hex>: <done> — reviewer(code-design) APPROVED
@@ -208,6 +293,8 @@ Phase: RED | GREEN | REFACTOR | SELF-DECLARE | REVIEWER(code-design) | COMMITTED
208293
<one actionable sentence>
209294
```
210295

296+
`## Cycle State` is updated at every phase transition. `## Self-Declaration` is replaced per-test cycle. Both sections are present only during Step 4; omit when in other steps.
297+
211298
---
212299

213300
## Roles
@@ -232,7 +319,6 @@ Phase: RED | GREEN | REFACTOR | SELF-DECLARE | REVIEWER(code-design) | COMMITTED
232319
| Class length | ≤ 50 lines |
233320
| Max nesting | 2 levels |
234321
| Instance variables per class | ≤ 2 |
235-
| Uncovered `@id` tags | 0 |
236322
| `noqa` comments | 0 |
237323
| `type: ignore` comments | 0 |
238324
| Orphaned tests | 0 |

0 commit comments

Comments
 (0)