You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(workflow): restructure features to single .feature files with Rule: blocks
- Replace folder-per-feature with one .feature file per feature
- User stories are now Rule: blocks; ACs are Example: blocks under each Rule
- Discovery content embedded in feature description free text
- Test layout: tests/features/<feature-name>/<rule-slug>_test.py
- Function naming: test_<rule_slug>_<id_hex>()
- Rewrite gen_test_stubs.py to parse Rule: blocks (one test file per Rule)
- Update gen_todo.py to find .feature files directly in in-progress/
- Update all skills: scope, tdd, implementation, verify, session-workflow
- Add mandatory Self-Declaration block in TODO.md at SELF-DECLARE phase
- Enforce Hypothesis @given + @pytest.mark.slow on all tests/unit/ tests
- Migrate completed/display-version to new single-file format
- Clarify OC-8: fix must produce a new named class, no workarounds
Copy file name to clipboardExpand all lines: .opencode/skills/implementation/SKILL.md
+56-54Lines changed: 56 additions & 54 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -57,36 +57,36 @@ Never write production code before picking a specific failing test. Never refact
57
57
If `packages` is missing or the directory does not exist, stop and resolve with the stakeholder before writing any code.
58
58
59
59
**Prerequisites — verify before starting:**
60
-
1.`docs/features/in-progress/` contains only `.gitkeep` (no feature folders). If another feature folder exists, **STOP** — another feature is already in progress.
61
-
2. The feature's `discovery.md` has `Status: BASELINED`. If not, escalate to the PO — Step 1 is incomplete.
62
-
3.At least one `.feature` file in the feature folder contains `Example:` blocks with`@id` tags. If not, escalate to PO — criteria have not been written.
60
+
1.`docs/features/in-progress/` contains only `.gitkeep` (no `.feature` files). If another `.feature` file exists, **STOP** — another feature is already in progress.
61
+
2. The feature file's discovery section has `Status: BASELINED`. If not, escalate to the PO — Step 1 is incomplete.
62
+
3.The feature file contains `Rule:` blocks with `Example:` blocks and`@id` tags. If not, escalate to PO — criteria have not been written.
63
63
64
64
**Steps:**
65
65
66
-
1. Move the feature folder from `backlog/` to `in-progress/`:
66
+
1. Move the feature file from `backlog/` to `in-progress/`:
2. Update `TODO.md` Source path from `backlog/` to `in-progress/`.
71
-
3. Read both `docs/features/discovery.md` (project-level) and the feature's `discovery.md`
71
+
3. Read both `docs/features/discovery.md` (project-level) and the feature file's discovery section
72
72
4. Run a silent pre-mortem: YAGNI, KISS, DRY, SOLID, Object Calisthenics, design patterns
73
-
5. Add the Architecture section to `docs/features/in-progress/<name>/discovery.md`:
73
+
5. Add the Architecture section to `docs/features/in-progress/<name>.feature` (append to the feature description, before the first `Rule:`):
74
74
75
-
```markdown
76
-
## Architecture
75
+
```gherkin
76
+
Architecture:
77
77
78
-
### Module Structure
79
-
-`<package>/domain/entity.py` — data classes and value objects
80
-
-`<package>/domain/service.py` — business logic
78
+
### Module Structure
79
+
- `<package>/domain/entity.py` — data classes and value objects
80
+
- `<package>/domain/service.py` — business logic
81
81
82
-
### Key Decisions
83
-
ADR-001: <title>
84
-
Decision: <what>
85
-
Reason: <whyinonesentence>
86
-
Alternatives considered: <whatwasrejectedandwhy>
82
+
### Key Decisions
83
+
ADR-001: <title>
84
+
Decision: <what>
85
+
Reason: <why in one sentence>
86
+
Alternatives considered: <what was rejected and why>
87
87
88
-
### Build Changes (needs PO approval: yes/no)
89
-
- New runtime dependency: <name> — reason: <why>
88
+
### Build Changes (needs PO approval: yes/no)
89
+
- New runtime dependency: <name> — reason: <why>
90
90
```
91
91
92
92
6.**Architecture contradiction check**: Compare each ADR against each AC. If any architectural decision contradicts or circumvents an acceptance criterion, flag it and resolve with the PO before writing any production code.
8. ≤ 2 instance variables — extract to value objects or split the class
150
+
8. ≤ 2 instance variables — if a class has 3+ `self.x` in `__init__`, group related
151
+
fields into a new named value object (Rule 3) or collection class (Rule 4). The fix
152
+
must produce a **new named class** — hardcoding constants, inlining literals,
153
+
using class-level variables, or moving fields to a parent class are all invalid
154
+
workarounds and remain FAIL.
151
155
9. No getters/setters — use commands (`activate()`) and queries (`is_active()`)
152
156
4.**Type hints**: add/fix type annotations on all public functions and classes
153
157
5.**Docstrings**: Google-style on all public functions and classes
@@ -185,6 +189,7 @@ After refactor, before moving to self-declaration:
185
189
| Bare `int`/`str` as domain concept | Wrap in value object | Verify no raw primitives in signatures |
186
190
| > 4 positional parameters | Group into dataclass | Verify parameter count |
187
191
|`list[X]` as domain collection | Wrap in collection class | Verify no bare lists |
192
+
| Class with 3+ `self.x` in `__init__`| Group related fields into a new named value object (OC-3) or collection class (OC-4) — **not** a dict, tuple, class variable, constant, or parent class | Count `self.` assignments again; each fix must produce a new named class |
188
193
189
194
```bash
190
195
uv run task test-fast # must still pass — the ONLY check during refactor
After refactor is complete and `test-fast` passes, complete this checklist before requesting the reviewer check. Include the filled-in checklist in your reviewer check request — this is the structured audit target the reviewer will verify against the actual code.
200
-
201
-
*For each item: check the box and cite `file:line` evidence, or explain why the rule does not apply to the code changed in this cycle.*
202
-
203
-
#### YAGNI
204
-
-[ ] No abstractions added beyond what the current acceptance criteria require
205
-
-[ ] No speculative parameters, flags, or extension points for hypothetical future use
204
+
After refactor is complete and `test-fast` passes, write the self-declaration **into `TODO.md`** under a `## Self-Declaration` block (replacing any prior one), then request the reviewer check. The reviewer will read `TODO.md` directly — do not paste the checklist into a separate message.
206
205
207
-
#### KISS
208
-
-[ ] Every function can be described in one sentence without "and"
209
-
-[ ] No unnecessary indirection, wrapper layers, or complexity
206
+
**Write this block into `TODO.md` now, filling in every item before requesting review:**
210
207
211
-
#### DRY
212
-
-[ ] No logic duplicated across functions or classes
213
-
-[ ] Shared concepts extracted into a single reusable location
214
-
215
-
#### SOLID
216
-
-[ ]**S** — each class/function has exactly one reason to change (`file:line`)
217
-
-[ ]**O** — new behavior added via extension, not by editing existing class bodies
218
-
-[ ]**L** — subtypes fully substitutable; no subtype narrows a contract or raises where base does not
219
-
-[ ]**I** — no Protocol/ABC forces unused method implementations
220
-
-[ ]**D** — domain classes import from abstractions (Protocols), not from I/O or framework layers directly
208
+
```markdown
209
+
## Self-Declaration (@id:<hex>)
210
+
-[ ] YAGNI-1: No abstractions beyond current AC — `file:line`
211
+
-[ ] YAGNI-2: No speculative parameters or flags for hypothetical future use — `file:line`
212
+
-[ ] KISS-1: Every function has one job, describable in one sentence without "and" — `file:line`
213
+
-[ ] KISS-2: No unnecessary indirection, wrapper layers, or complexity — `file:line`
214
+
-[ ] DRY-1: No logic block duplicated across two or more locations — `file:line`
215
+
-[ ] DRY-2: Every shared concept extracted to exactly one place — `file:line`
216
+
-[ ] SOLID-S: Each class/function has one reason to change — `file:line`
217
+
-[ ] SOLID-O: New behavior added by extension, no existing class body edited — `file:line` or N/A
218
+
-[ ] SOLID-L: Every subtype fully substitutable; no narrowed contract or surprise raise — `file:line` or N/A
219
+
-[ ] SOLID-I: No Protocol/ABC forces an implementor to leave a method as `...` or raise — `file:line` or N/A
220
+
-[ ] SOLID-D: Domain classes depend on Protocols, not on I/O or framework imports directly — `file:line`
221
+
-[ ] OC-1: Max one indent level per method; inner blocks extracted to named helpers — deepest: `file:line`
222
+
-[ ] OC-2: No `else` after `return`; all branches return early and the happy path is flat — `file:line` or N/A
223
+
-[ ] OC-3: No bare `int`/`str`/`float` as domain concepts in public signatures; each wrapped in a named type — `file:line` or N/A
224
+
-[ ] OC-4: No bare `list[X]`/`set[X]` as domain values; each wrapped in a named collection class — `file:line` or N/A
225
+
-[ ] OC-5: No `a.b.c()` chains; each dot navigation step assigned to a named local — `file:line` or N/A
226
+
-[ ] OC-6: No abbreviations anywhere; every name is a full word readable without context — `file:line` or N/A
227
+
-[ ] OC-7: Every function ≤ 20 lines, every class ≤ 50 lines — longest: `file:line`
228
+
-[ ] OC-8: Every class has ≤ 2 `self.x` in `__init__`; if > 2 before this cycle, name the new value object extracted and cite `file:line` per class
229
+
-[ ] OC-9: No `get_x()`/`set_x()` pairs; state changes via commands, queries return values — `file:line` or N/A
230
+
-[ ] Semantic: test Given/When/Then operates at the same abstraction level as the AC — `file:line`
231
+
```
221
232
222
-
#### Object Calisthenics
223
-
-[ ] Rule 1 — one indent level per method (`file:line` of deepest nesting)
224
-
-[ ] Rule 2 — no `else` after `return`; early returns only
225
-
-[ ] Rule 3 — primitives wrapped: no bare `int`/`str` as domain concepts in public signatures
226
-
-[ ] Rule 4 — collections wrapped: no bare `list[X]` as domain values
227
-
-[ ] Rule 5 — one dot per line: no `a.b.c()` chains
*For every item: check the box AND cite `file:line` evidence, or write `N/A` with a one-line reason. An unchecked box or missing evidence is an automatic REJECTED.*
232
234
233
235
Update `## Cycle State` Phase: `SELF-DECLARE`
234
236
235
237
## REVIEWER CHECK — Code Design Only
236
238
237
-
After each test goes green + refactor + self-declaration, **STOP** and request a reviewer check. Include the filled-in Design Self-Declaration checklist in your request.
239
+
After each test goes green + refactor + self-declaration, **STOP** and request a reviewer check. The reviewer will read the `## Self-Declaration` block from `TODO.md` directly — point them to it.
238
240
239
241
**STOP — request a reviewer check of code design and semantic alignment.**
240
242
**WAIT for APPROVED before committing.**
241
243
242
244
The reviewer is scoped to **code design only** (not full Step 5):
243
245
244
-
**What the reviewer receives**: The developer's completed Design Self-Declaration with `file:line` evidence for each rule.
246
+
**What the reviewer receives**: The developer's completed `## Self-Declaration` block in `TODO.md`, with `file:line` evidence for each rule.
245
247
246
248
**What the reviewer does**: Independently inspects the actual code for each rule the developer claimed compliant. The self-declaration is an audit target — the reviewer verifies claims, not just reads them.
247
249
@@ -307,7 +309,7 @@ If during implementation you discover a behavior not covered by existing accepta
307
309
- Note the gap in TODO.md under `## Next`
308
310
- The PO will decide whether to add a new Example to the `.feature` file
309
311
310
-
Extra tests in `tests/unit/` are allowed freely (coverage, edge cases, etc.) — these do not need `@id` traceability.
312
+
Extra tests in `tests/unit/` are allowed freely (coverage, edge cases, etc.) — these do not need `@id` traceability.**Every test in `tests/unit/` must be a Hypothesis property test: `@given` is required, `@pytest.mark.slow` is mandatory, plain `assert` tests without `@given` are forbidden.**
0 commit comments