|
| 1 | +# Development Workflow |
| 2 | + |
| 3 | +This document describes the complete feature lifecycle used to develop software with this framework. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## Overview |
| 8 | + |
| 9 | +Features flow through 6 steps with a WIP limit of 1 feature at a time. The filesystem enforces the limit: |
| 10 | + |
| 11 | +``` |
| 12 | +docs/features/backlog/<name>.feature ← waiting |
| 13 | +docs/features/in-progress/<name>.feature ← exactly one being built |
| 14 | +docs/features/completed/<name>.feature ← accepted and shipped |
| 15 | +``` |
| 16 | + |
| 17 | +Each step has a designated agent and a specific deliverable. No step is skipped. |
| 18 | + |
| 19 | +--- |
| 20 | + |
| 21 | +## Full Workflow Diagram |
| 22 | + |
| 23 | +``` |
| 24 | +╔══════════════════════════════════════════════════════════════════════╗ |
| 25 | +║ FEATURE LIFECYCLE (WIP = 1) ║ |
| 26 | +╚══════════════════════════════════════════════════════════════════════╝ |
| 27 | +
|
| 28 | + FILESYSTEM ENFORCES WIP: |
| 29 | + backlog/<name>.feature → in-progress/<name>.feature → completed/<name>.feature |
| 30 | +
|
| 31 | +
|
| 32 | +┌─────────────────────────────────────────────────────────────────────┐ |
| 33 | +│ STEP 1 — SCOPE agent: product-owner │ |
| 34 | +├─────────────────────────────────────────────────────────────────────┤ |
| 35 | +│ │ |
| 36 | +│ Phase 1 — Project Discovery (once per project) │ |
| 37 | +│ PO asks stakeholder 7 questions → silent pre-mortem │ |
| 38 | +│ → baseline → create backlog/<name>.feature stubs │ |
| 39 | +│ │ |
| 40 | +│ Phase 2 — Feature Discovery (per feature) │ |
| 41 | +│ PO populates Entities table → generates questions from gaps │ |
| 42 | +│ → interview rounds → stakeholder says "baseline" │ |
| 43 | +│ → decomposition check (>2 concerns or >8 examples → split) │ |
| 44 | +│ │ |
| 45 | +│ Phase 3 — Stories (PO alone) │ |
| 46 | +│ Write Rule: blocks with user story headers (no Examples yet) │ |
| 47 | +│ commit: feat(stories): write user stories for <name> │ |
| 48 | +│ │ |
| 49 | +│ Phase 4 — Criteria (PO alone) │ |
| 50 | +│ Write @id-tagged Example: blocks under each Rule: │ |
| 51 | +│ commit: feat(criteria): write acceptance criteria for <name> │ |
| 52 | +│ ★ FROZEN — changes require @deprecated + new Example │ |
| 53 | +│ │ |
| 54 | +└─────────────────────────────────────────────────────────────────────┘ |
| 55 | + ↓ PO picks feature from backlog |
| 56 | +┌─────────────────────────────────────────────────────────────────────┐ |
| 57 | +│ STEP 2 — ARCHITECTURE agent: developer │ |
| 58 | +├─────────────────────────────────────────────────────────────────────┤ |
| 59 | +│ │ |
| 60 | +│ mv backlog/<name>.feature → in-progress/<name>.feature │ |
| 61 | +│ Read discovery + feature file │ |
| 62 | +│ Silent pre-mortem (YAGNI/KISS/DRY/SOLID/OC/patterns) │ |
| 63 | +│ Append Architecture section to feature file description │ |
| 64 | +│ (Module Structure + ADRs + Build Changes) │ |
| 65 | +│ Architecture contradiction check → PO acknowledges │ |
| 66 | +│ commit: feat(<name>): add architecture │ |
| 67 | +│ │ |
| 68 | +└─────────────────────────────────────────────────────────────────────┘ |
| 69 | + ↓ |
| 70 | +┌─────────────────────────────────────────────────────────────────────┐ |
| 71 | +│ STEP 3 — TEST FIRST agent: developer │ |
| 72 | +├─────────────────────────────────────────────────────────────────────┤ |
| 73 | +│ │ |
| 74 | +│ uv run task gen-tests → creates tests/features/<name>/ │ |
| 75 | +│ one <rule-slug>_test.py per Rule: │ |
| 76 | +│ test_<rule_slug>_<hex>() per Example │ |
| 77 | +│ Write test bodies (real assertions, not raise NotImplementedError) │ |
| 78 | +│ Confirm every test FAILS (ImportError / AssertionError) │ |
| 79 | +│ ★ STOP — reviewer checks test design + semantic alignment │ |
| 80 | +│ ★ WAIT for APPROVED │ |
| 81 | +│ commit: test(<name>): write failing tests │ |
| 82 | +│ │ |
| 83 | +└─────────────────────────────────────────────────────────────────────┘ |
| 84 | + ↓ |
| 85 | +┌─────────────────────────────────────────────────────────────────────┐ |
| 86 | +│ STEP 4 — IMPLEMENT agent: developer │ |
| 87 | +├─────────────────────────────────────────────────────────────────────┤ |
| 88 | +│ │ |
| 89 | +│ For each failing test (one at a time): │ |
| 90 | +│ │ |
| 91 | +│ RED → GREEN → REFACTOR → SELF-DECLARE ─STOP─ REVIEWER ─WAIT─ │ |
| 92 | +│ ↓ APPROVED │ |
| 93 | +│ COMMIT │ |
| 94 | +│ ↓ │ |
| 95 | +│ next test │ |
| 96 | +│ │ |
| 97 | +│ RED: confirm test fails │ |
| 98 | +│ GREEN: minimum code to pass (YAGNI + KISS only) │ |
| 99 | +│ REFACTOR: DRY → SOLID → Object Calisthenics (9 rules) │ |
| 100 | +│ → type hints → docstrings │ |
| 101 | +│ SELF-DECLARE: write ## Self-Declaration block in TODO.md │ |
| 102 | +│ 21-item checklist with file:line evidence │ |
| 103 | +│ REVIEWER: code-design check only (no lint/pyright/coverage) │ |
| 104 | +│ COMMIT: feat(<name>): implement <what> │ |
| 105 | +│ │ |
| 106 | +│ After all tests green: │ |
| 107 | +│ lint + static-check + test + timeout run (all must pass) │ |
| 108 | +│ developer pre-mortem (2-3 sentences) │ |
| 109 | +│ │ |
| 110 | +└─────────────────────────────────────────────────────────────────────┘ |
| 111 | + ↓ |
| 112 | +┌─────────────────────────────────────────────────────────────────────┐ |
| 113 | +│ STEP 5 — VERIFY agent: reviewer │ |
| 114 | +├─────────────────────────────────────────────────────────────────────┤ |
| 115 | +│ │ |
| 116 | +│ Default hypothesis: broken despite green checks │ |
| 117 | +│ │ |
| 118 | +│ 1. Read feature file — all @id Examples, interaction model │ |
| 119 | +│ 2. Check commit history — one commit per test, clean status │ |
| 120 | +│ 3. Production-grade gate: │ |
| 121 | +│ app exits cleanly + output changes with input │ |
| 122 | +│ 4. Code review (stop on first failure): │ |
| 123 | +│ 4a Correctness (dead code, DRY, YAGNI) │ |
| 124 | +│ 4b KISS (one thing, nesting, size) │ |
| 125 | +│ 4c SOLID (5-row table) │ |
| 126 | +│ 4d Object Calisthenics (9-row table) │ |
| 127 | +│ 4e Design Patterns (5 smells) │ |
| 128 | +│ 4f Tests (docstrings, contracts, @id coverage, naming) │ |
| 129 | +│ 4g Code Quality (noqa, type hints, docstrings, coverage) │ |
| 130 | +│ 5. Run: gen-tests --orphans → lint → static-check → test │ |
| 131 | +│ 6. Interactive verification (if UI involved) │ |
| 132 | +│ 7. Written report: APPROVED or REJECTED │ |
| 133 | +│ │ |
| 134 | +└─────────────────────────────────────────────────────────────────────┘ |
| 135 | + ↓ APPROVED |
| 136 | +┌─────────────────────────────────────────────────────────────────────┐ |
| 137 | +│ STEP 6 — ACCEPT agent: product-owner │ |
| 138 | +├─────────────────────────────────────────────────────────────────────┤ |
| 139 | +│ │ |
| 140 | +│ PO runs/observes the feature (real user interaction) │ |
| 141 | +│ Checks against original Rule: user stories │ |
| 142 | +│ │ |
| 143 | +│ ACCEPTED: │ |
| 144 | +│ mv in-progress/<name>.feature → completed/<name>.feature │ |
| 145 | +│ developer creates PR + tags release │ |
| 146 | +│ │ |
| 147 | +│ REJECTED: │ |
| 148 | +│ feedback in TODO.md → back to relevant step │ |
| 149 | +│ │ |
| 150 | +└─────────────────────────────────────────────────────────────────────┘ |
| 151 | +``` |
| 152 | + |
| 153 | +--- |
| 154 | + |
| 155 | +## Supporting Tools |
| 156 | + |
| 157 | +| Command | When | Purpose | |
| 158 | +|---|---|---| |
| 159 | +| `uv run task gen-tests` | Step 3, Step 4 | Reads `.feature` files → creates/syncs test stubs in `tests/features/` | |
| 160 | +| `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` | |
| 162 | +| `uv run task gen-todo` | Every session | Reads in-progress `.feature` → syncs `TODO.md` | |
| 163 | +| `uv run task gen-id` | Step 1 Phase 4 | Generate 8-char hex `@id` for a new Example | |
| 164 | +| `uv run task test-fast` | Step 4 cycle | Fast test run (no coverage) — used during Red-Green-Refactor | |
| 165 | +| `uv run task test` | Handoff, Step 5 | Full suite with coverage — must reach 100% | |
| 166 | +| `uv run task lint` | Handoff, Step 5 | ruff — must exit 0 | |
| 167 | +| `uv run task static-check` | Handoff, Step 5 | pyright — must exit 0, 0 errors | |
| 168 | +| `timeout 10s uv run task run` | Handoff, Step 5 | App must exit cleanly (exit 124 = hang = fix it) | |
| 169 | + |
| 170 | +--- |
| 171 | + |
| 172 | +## Test Layout |
| 173 | + |
| 174 | +``` |
| 175 | +tests/ |
| 176 | + features/<feature-name>/ |
| 177 | + <rule-slug>_test.py ← generated by gen-tests, one per Rule: block |
| 178 | + function: test_<rule_slug>_<8char_hex>() |
| 179 | + unit/ |
| 180 | + <anything>_test.py ← developer-authored extras, no @id traceability |
| 181 | + plain pytest or Hypothesis @given (developer's choice) |
| 182 | +``` |
| 183 | + |
| 184 | +--- |
| 185 | + |
| 186 | +## TODO.md Structure (Step 4) |
| 187 | + |
| 188 | +```markdown |
| 189 | +# Current Work |
| 190 | + |
| 191 | +Feature: <name> |
| 192 | +Step: 4 (implement) |
| 193 | +Source: docs/features/in-progress/<name>.feature |
| 194 | + |
| 195 | +## Cycle State |
| 196 | +Test: @id:<hex> — <description> |
| 197 | +Phase: RED | GREEN | REFACTOR | SELF-DECLARE | REVIEWER(code-design) | COMMITTED |
| 198 | + |
| 199 | +## Self-Declaration (@id:<hex>) |
| 200 | +- [x] YAGNI-1 … SOLID-D … OC-1…OC-9 … Semantic (21 items, file:line each) |
| 201 | + |
| 202 | +## Progress |
| 203 | +- [x] @id:<hex>: <done> — reviewer(code-design) APPROVED |
| 204 | +- [~] @id:<hex>: <in progress> |
| 205 | +- [ ] @id:<hex>: <next> |
| 206 | + |
| 207 | +## Next |
| 208 | +<one actionable sentence> |
| 209 | +``` |
| 210 | + |
| 211 | +--- |
| 212 | + |
| 213 | +## Roles |
| 214 | + |
| 215 | +| Role | Type | Responsibilities | |
| 216 | +|---|---|---| |
| 217 | +| **Stakeholder** | Human | Answers questions, provides domain knowledge, says "baseline" | |
| 218 | +| **Product Owner** | AI agent | Interviews stakeholder, writes `.feature` files, picks features, accepts deliveries | |
| 219 | +| **Developer** | AI agent | Architecture, tests, code, git, releases | |
| 220 | +| **Reviewer** | AI agent | Adversarial verification — defaults to REJECTED until proven correct | |
| 221 | + |
| 222 | +--- |
| 223 | + |
| 224 | +## Quality Gates (non-negotiable) |
| 225 | + |
| 226 | +| Gate | Standard | |
| 227 | +|---|---| |
| 228 | +| Test coverage | 100% | |
| 229 | +| Type errors (pyright) | 0 | |
| 230 | +| Lint errors (ruff) | 0 | |
| 231 | +| Function length | ≤ 20 lines | |
| 232 | +| Class length | ≤ 50 lines | |
| 233 | +| Max nesting | 2 levels | |
| 234 | +| Instance variables per class | ≤ 2 | |
| 235 | +| Uncovered `@id` tags | 0 | |
| 236 | +| `noqa` comments | 0 | |
| 237 | +| `type: ignore` comments | 0 | |
| 238 | +| Orphaned tests | 0 | |
| 239 | +| Hypothesis tests missing `@pytest.mark.slow` | 0 | |
0 commit comments