konductor 0.10.0 → 0.12.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "konductor",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "Spec-driven development orchestrator for Kiro CLI — MCP server and hook processor",
5
5
  "bin": {
6
6
  "konductor": "bin/konductor"
@@ -10,13 +10,13 @@ You are the Konductor orchestrator. Execute the plans for a phase by spawning ex
10
10
  ## Critical Rules
11
11
 
12
12
  1. **Only YOU manage state transitions** — use the MCP tools (`state_get`, `state_transition`, `state_add_blocker`) instead of writing `state.toml` directly. Subagents write their own output files (summary files, result files).
13
- 2. **Read `config.toml` first** — respect parallelism settings and git configuration.
13
+ 2. **Read config via MCP** — call `config_get` to get parallelism settings and git configuration.
14
14
  3. **Report errors, don't retry crashes** — if an executor fails, write an error result for that plan, continue with remaining plans, and report all failures at the end.
15
15
  4. **Resume support** — scan for existing summary files to skip completed plans.
16
16
 
17
17
  ## Step 1: Read State and Config
18
18
 
19
- Call the `state_get` MCP tool to read current state, and read `.konductor/config.toml` for execution settings (parallelism, git config).
19
+ Call the `state_get` MCP tool to read current state, and call the `config_get` MCP tool for execution settings (parallelism, git config).
20
20
 
21
21
  Validate that `[current].step` is either:
22
22
  - `"planned"` — ready to start execution
@@ -10,7 +10,11 @@ You are the Konductor orchestrator. Initialize a new spec-driven development pro
10
10
  ## Step 1: Check Existing State
11
11
 
12
12
  Check if `.konductor/` directory already exists.
13
- - If it exists, call the `state_get` MCP tool. If it returns valid state, warn the user: "A Konductor project already exists here. Reinitializing will overwrite project.md, requirements.md, and roadmap.md. Proceed? (y/n)"
13
+ - If it exists, call the `state_get` MCP tool. If it returns valid state:
14
+ - If `current.step` is `"shipped"`: ask the user: "Project is shipped. Do you want to (a) add a new phase to the existing project, or (b) reinitialize from scratch?"
15
+ - If (a): ask for the new phase name. Read `.konductor/roadmap.md` to determine the updated `phases_total`. Call the `state_advance_phase` MCP tool with the new phase identifier and updated phases_total. Skip to Step 8 (report success).
16
+ - If (b): proceed with normal reinitialization below.
17
+ - Otherwise: warn the user: "A Konductor project already exists here. Reinitializing will overwrite project.md, requirements.md, and roadmap.md. Proceed? (y/n)"
14
18
  - If user declines, stop.
15
19
 
16
20
  ## Step 2: Create Directory Structure
@@ -62,23 +66,7 @@ Call the `state_init` MCP tool with:
62
66
 
63
67
  This creates `.konductor/state.toml` with the correct initial structure.
64
68
 
65
- Write `.konductor/config.toml`:
66
- ```toml
67
- [general]
68
- default_model = "claude-sonnet-4"
69
-
70
- [execution]
71
- max_wave_parallelism = 4
72
-
73
- [git]
74
- auto_commit = true
75
- branching_strategy = "none"
76
-
77
- [features]
78
- research = true
79
- plan_checker = true
80
- verifier = true
81
- ```
69
+ Call the `config_init` MCP tool to create `.konductor/config.toml` with defaults.
82
70
 
83
71
  ## Step 7: Sync Steering Files
84
72
 
@@ -88,7 +88,6 @@ mkdir -p .kiro/steering
88
88
  Provide the mapper with:
89
89
  - The target directory (absolute path)
90
90
  - The output file paths (absolute paths)
91
- - Reference to `references/codebase-analysis.md` if it exists
92
91
 
93
92
  Wait for the mapper to complete.
94
93
 
@@ -149,11 +148,7 @@ These files will be used as context for planning and execution.
149
148
 
150
149
  ## Step 7: Optional State Update
151
150
 
152
- If a Konductor project exists (`.konductor/state.toml`), update the metrics:
153
- - Increment `[metrics].total_agent_sessions`
154
- - Update `[metrics].last_activity`
155
-
156
- Write a result file at `.konductor/.results/map-codebase.toml`:
151
+ If a Konductor project exists (`.konductor/state.toml`), write a result file at `.konductor/.results/map-codebase.toml`:
157
152
 
158
153
  ```toml
159
154
  step = "map"
@@ -11,13 +11,13 @@ You are the Konductor orchestrator. Your job is to determine the next step in th
11
11
 
12
12
  1. **Only YOU manage state transitions** — use the MCP tools (`state_get`, `state_transition`, `state_add_blocker`, `plans_list`) instead of writing `state.toml` directly. Subagents never touch state. They write their own output files.
13
13
  2. **`.results/` is the source of truth** — if state and `.results/` conflict, trust `.results/`.
14
- 3. **Read `config.toml` first** — respect feature flags and parallelism settings.
14
+ 3. **Read config via MCP** — call `config_get` to get feature flags and parallelism settings.
15
15
  4. **Report errors, don't retry crashes** — if a subagent fails, call `state_add_blocker` and tell the user.
16
16
 
17
17
  ## Step 1: Read State
18
18
 
19
19
  Call the `state_get` MCP tool to read current state. Also read:
20
- - `.konductor/config.toml` feature flags and settings
20
+ - Call the `config_get` MCP tool for feature flags and settings
21
21
  - `.konductor/roadmap.md` — phase list and status
22
22
 
23
23
  If `.konductor/` does not exist, tell the user:
@@ -151,9 +151,17 @@ Current phase is done. Check roadmap for next incomplete phase:
151
151
  - If found: update phase via `state_transition` with the new phase, set `step = "initialized"`, run Planning Pipeline.
152
152
  - If all phases complete: tell user "All phases complete! Say 'ship' to finalize."
153
153
 
154
+ ### Case: `step = "shipped"`
155
+
156
+ The project has been shipped. Check `.konductor/roadmap.md` for any phases not yet completed.
157
+
158
+ - If a new phase exists in the roadmap that hasn't been executed: call the `state_advance_phase` MCP tool with the new phase identifier and the updated `phases_total` from the roadmap. This preserves project history (phases_complete, initialized date, metrics, blockers) while starting the new phase. Then run the Planning Pipeline for the new phase.
159
+ - If no new phases exist: tell the user "All phases complete and shipped! To continue, add new phases to roadmap.md and requirements.md, then say 'next' again."
160
+
154
161
  ### Case: `step = "blocked"`
155
162
 
156
- Tell the user about the blocker from the `state_get` response `blockers` list and ask how to proceed.
163
+ Tell the user about the blocker from the `state_get` response `blockers` list. Suggest:
164
+ > "To unblock, fix the underlying issue, then call the `state_resolve_blocker` MCP tool with the phase to clear the blocker. After that, say 'next' to continue."
157
165
 
158
166
  ## Step 3: Error Handling
159
167
 
@@ -10,13 +10,18 @@ You are the Konductor orchestrator. Plan a phase by researching the ecosystem, c
10
10
  ## Critical Rules
11
11
 
12
12
  1. **Only YOU manage state transitions** — use the MCP tools (`state_get`, `state_transition`, `state_add_blocker`) instead of writing `state.toml` directly. Subagents write their own output files.
13
- 2. **Read `config.toml` first** — respect feature flags (research, plan_checker, design_review).
13
+ 2. **Read config via MCP** — call `config_get` to get feature flags (research, plan_checker, design_review).
14
14
  3. **Report errors, don't retry crashes** — if a subagent fails, set status to "blocked".
15
15
  4. **Accept a phase argument** — the user may say "plan phase 01" or "plan phase 01-auth-system". Resolve short form by scanning `.konductor/phases/` directories.
16
16
 
17
17
  ## Step 1: Validate State
18
18
 
19
- Call the `state_get` MCP tool to read current state, and read `.konductor/config.toml`.
19
+ Call the `state_get` MCP tool to read current state, and call the `config_get` MCP tool to read configuration.
20
+
21
+ Validate that `current.step` is `"initialized"` or `"discussed"`. If not, tell the user:
22
+ > "Phase {phase} is not ready for planning. Current step: {step}. Run 'discuss' or 'init' first."
23
+ Then stop.
24
+
20
25
  Validate that the specified phase exists in `.konductor/roadmap.md`.
21
26
  Create the phase directory if it doesn't exist:
22
27
  ```bash
@@ -112,6 +117,9 @@ Wait for the reviewer to complete. Verify `review.md` was created.
112
117
  3. Re-run the **konductor-design-reviewer**
113
118
  4. Maximum 2 review-revise iterations. If still "revise" after 2 iterations, proceed to user approval with warnings noted.
114
119
 
120
+ **If verdict is "reject":** Stop. Do not advance state. Tell the user:
121
+ > "Design rejected by reviewer. See `.konductor/phases/{phase}/review.md` for details. Fix the fundamental issues and re-run planning."
122
+
115
123
  **Present the review summary to the user.** Ask:
116
124
  > "Approve plans for execution? (approve / reject)"
117
125
 
@@ -38,7 +38,7 @@ Spawn the **konductor-verifier** agent with instructions to perform a cross-phas
38
38
  - Check that API contracts are honored
39
39
  - Test critical user flows that span multiple phases
40
40
  - Look for integration gaps or inconsistencies between phase boundaries
41
- - Reference: see `references/verification.md` for verification patterns
41
+ - Reference: see `skills/konductor-verify/references/verification-patterns.md` for verification patterns
42
42
 
43
43
  Provide the verifier with:
44
44
  - All phase directories: `.konductor/phases/*/`
@@ -95,8 +95,9 @@ Last activity: {last_activity_relative} ({last_activity_absolute})
95
95
  - `planned` → "Say 'exec' to execute the plans."
96
96
  - `executing` → "Execution in progress. Wait for completion or check logs."
97
97
  - `executed` → "Say 'next' to verify the phase."
98
- - `verified` → "Say 'next' to mark phase complete and advance."
99
98
  - `complete` → "Phase {n} complete. Say 'next' to move to phase {n+1}."
99
+ - `shipped` → "All phases shipped. Add new phases to roadmap.md or say 'init' to start a new project."
100
+ - `blocked` → "Resolve the blocker with `state_resolve_blocker`, then say 'next'."
100
101
 
101
102
  ## Error Handling
102
103
 
@@ -10,13 +10,13 @@ You are the Konductor orchestrator. Verify a phase after execution to validate t
10
10
  ## Critical Rules
11
11
 
12
12
  1. **Only YOU manage state transitions** — use the MCP tools (`state_get`, `state_transition`, `state_add_blocker`) instead of writing `state.toml` directly. Subagents write their own output files.
13
- 2. **Read `config.toml` first** — respect feature flags and settings.
13
+ 2. **Read config via MCP** — call `config_get` to get feature flags and settings.
14
14
  3. **Report errors, don't retry crashes** — if the verifier fails, set status to "blocked".
15
15
  4. **Use the 3-level verification framework** — Exists, Substantive, Wired (see references/verification-patterns.md).
16
16
 
17
17
  ## Step 1: Read State and Validate Phase
18
18
 
19
- Call the `state_get` MCP tool to read current state, and read `.konductor/config.toml` for verification settings.
19
+ Call the `state_get` MCP tool to read current state, and call the `config_get` MCP tool for verification settings.
20
20
 
21
21
  Validate that `[current].step` is `"executed"`.
22
22
 
@@ -1,400 +0,0 @@
1
- # Verification Patterns — 3-Level Verification Framework
2
-
3
- This guide defines how to verify that phase execution actually achieved its goals, not just created files.
4
-
5
- ## The Three Levels
6
-
7
- Verification proceeds in three increasingly rigorous levels:
8
-
9
- ### Level 1: Exists
10
- **Question:** Is the artifact present?
11
-
12
- **Checks:**
13
- - File exists at expected path
14
- - Directory structure is correct
15
- - Database tables exist
16
- - API endpoints are defined
17
-
18
- **Commands:**
19
- ```bash
20
- # File existence
21
- [ -f src/models/user.rs ] && echo "OK" || echo "MISSING"
22
-
23
- # Directory structure
24
- [ -d src/routes ] && [ -d src/models ] && echo "OK"
25
-
26
- # Database table (PostgreSQL)
27
- psql -d mydb -c "\dt users" | grep -q users && echo "OK"
28
-
29
- # API endpoint defined (grep for route definition)
30
- grep -r "POST.*auth/register" src/routes/ && echo "OK"
31
- ```
32
-
33
- **When Level 1 fails:** The most basic requirement is unmet. Execution did not complete.
34
-
35
- ### Level 2: Substantive
36
- **Question:** Is the artifact a real implementation, not a stub?
37
-
38
- **Checks:**
39
- - File has meaningful content (>minimum line count)
40
- - Not just comments or placeholders
41
- - No TODO/FIXME/PLACEHOLDER patterns
42
- - Contains expected code structures (functions, classes, exports)
43
-
44
- **Thresholds:**
45
- - Model files: >20 lines
46
- - Route handlers: >15 lines
47
- - Component files: >25 lines
48
- - Test files: >30 lines
49
- - Migration files: >10 lines
50
-
51
- **Anti-patterns to detect:**
52
- ```rust
53
- // STUB: Not substantive
54
- pub struct User {
55
- // TODO: implement fields
56
- }
57
-
58
- // REAL: Substantive
59
- pub struct User {
60
- pub id: Uuid,
61
- pub email: String,
62
- password_hash: String,
63
- created_at: DateTime<Utc>,
64
- }
65
- ```
66
-
67
- **Commands:**
68
- ```bash
69
- # Line count check (exclude comments)
70
- lines=$(grep -v '^[[:space:]]*#' src/models/user.rs | grep -v '^[[:space:]]*$' | wc -l)
71
- [ "$lines" -gt 20 ] && echo "OK" || echo "STUB"
72
-
73
- # TODO/FIXME detection
74
- grep -i 'TODO\|FIXME\|PLACEHOLDER\|STUB' src/models/user.rs && echo "INCOMPLETE"
75
-
76
- # Meaningful structure (has at least one pub fn)
77
- grep -q 'pub fn' src/models/user.rs && echo "OK"
78
- ```
79
-
80
- **When Level 2 fails:** Execution created files but didn't implement them properly. This is common with autonomous executors that hit errors.
81
-
82
- ### Level 3: Wired
83
- **Question:** Is the artifact connected to the rest of the system?
84
-
85
- **Checks:**
86
- - Imported by other files
87
- - Actually used (not just imported)
88
- - Part of the call graph
89
- - No orphaned code
90
-
91
- **Common wiring patterns:**
92
-
93
- **Component → API fetch:**
94
- ```javascript
95
- // In component file
96
- import { fetchUsers } from '../api/users'
97
- // And uses it
98
- const users = await fetchUsers()
99
- ```
100
-
101
- **API → Database query:**
102
- ```python
103
- # In API handler
104
- from models.user import User
105
- # And uses it
106
- user = User.query.filter_by(email=email).first()
107
- ```
108
-
109
- **Form → Handler:**
110
- ```rust
111
- // In form component
112
- <form action="/auth/register" method="POST">
113
- // And in routes
114
- pub async fn register(form: Form<RegisterData>) -> Response
115
- ```
116
-
117
- **State → Render:**
118
- ```jsx
119
- // In state file
120
- export const userSlice = createSlice({ ... })
121
- // And in component
122
- import { selectUser } from '../store/userSlice'
123
- const user = useSelector(selectUser)
124
- ```
125
-
126
- **Commands:**
127
- ```bash
128
- # Check if User model is imported anywhere
129
- grep -r "use.*models::user" src/ --exclude-dir=models | wc -l
130
-
131
- # Check if User is actually used (not just imported)
132
- # Look for User:: or User.new or similar
133
- grep -r "User::\|User\.new\|User\.find" src/ | wc -l
134
-
135
- # Check bidirectional wiring (component imports API, API returns component data)
136
- grep -q "fetchUsers" src/components/UserList.tsx && \
137
- grep -q "export.*fetchUsers" src/api/users.ts && echo "WIRED"
138
- ```
139
-
140
- **When Level 3 fails:** Execution implemented features but they're isolated. Integration work is missing.
141
-
142
- ## Must-Haves Derivation
143
-
144
- Every plan should have a `must_haves` section in its frontmatter:
145
-
146
- ```toml
147
- [must_haves]
148
- truths = [...]
149
- artifacts = [...]
150
- key_links = [...]
151
- ```
152
-
153
- Verification uses these to determine what to check.
154
-
155
- ### Option A: From Plan Frontmatter
156
-
157
- If the plan has a `must_haves` section, use it directly.
158
-
159
- **Example plan frontmatter:**
160
- ```toml
161
- [must_haves]
162
- truths = ["Users can register with email", "Passwords are hashed"]
163
- artifacts = ["src/models/user.rs", "src/routes/auth.rs"]
164
- key_links = ["User imported by auth routes", "bcrypt used in user.rs"]
165
- ```
166
-
167
- **Verification:**
168
- 1. For each truth, derive a test (manual or automated)
169
- 2. For each artifact, check Levels 1-3
170
- 3. For each key_link, verify the connection exists
171
-
172
- ### Option B: From Roadmap Success Criteria
173
-
174
- If the plan doesn't have `must_haves`, fall back to the phase's success criteria from `roadmap.md`.
175
-
176
- **Example roadmap:**
177
- ```markdown
178
- ## Phase 01: Authentication System
179
-
180
- Success criteria:
181
- - Users can register with email and password
182
- - Users can log in and receive a session token
183
- - Passwords are securely hashed
184
- ```
185
-
186
- **Derive must_haves:**
187
- - **truths:** Each success criterion becomes a truth
188
- - **artifacts:** Infer from common patterns (User model, auth routes, migrations)
189
- - **key_links:** Infer from dependencies (auth routes use User model)
190
-
191
- ### Option C: Goal-Backward Derivation
192
-
193
- If neither plan frontmatter nor roadmap success criteria are available, work backward from the phase goal.
194
-
195
- **Steps:**
196
- 1. Read the phase goal from roadmap.md
197
- 2. Ask: "What must be true for this goal to be achieved?"
198
- 3. Ask: "What files must exist?"
199
- 4. Ask: "How must those files be connected?"
200
-
201
- **Example:**
202
- - **Goal:** "Implement user authentication"
203
- - **Truths:** Users can register, Users can log in, Sessions are managed
204
- - **Artifacts:** User model, auth routes, session middleware
205
- - **Key links:** Auth routes import User, Middleware validates sessions
206
-
207
- ## Gap Structuring
208
-
209
- When verification finds issues, structure them as "gaps" for the next planning cycle.
210
-
211
- **Gap format:**
212
- ```toml
213
- [[gaps]]
214
- truth = "Users can register with email"
215
- status = "failed"
216
- reason = "Registration endpoint returns 500"
217
- artifacts = ["src/routes/auth.rs"]
218
- missing = ["Error handling", "Email validation"]
219
- ```
220
-
221
- **Fields:**
222
- - `truth`: Which must_have truth failed
223
- - `status`: "failed" or "partial" or "incomplete"
224
- - `reason`: Specific error or issue
225
- - `artifacts`: Which files are involved
226
- - `missing`: What needs to be added/fixed
227
-
228
- **Write gaps to:** `.konductor/phases/{phase}/gaps.toml`
229
-
230
- The next planning cycle can read this file and create gap-closure plans.
231
-
232
- ## Verification Commands by Language
233
-
234
- ### Rust
235
- ```bash
236
- # Compilation check
237
- cargo check
238
-
239
- # Test execution
240
- cargo test
241
-
242
- # Import check
243
- grep -r "use crate::models::User" src/
244
-
245
- # Usage check
246
- grep -r "User::" src/ | grep -v "^src/models/user.rs"
247
- ```
248
-
249
- ### Python
250
- ```bash
251
- # Import check
252
- python -c "from models.user import User; print('OK')"
253
-
254
- # Test execution
255
- pytest tests/
256
-
257
- # Import usage
258
- grep -r "from models.user import" src/ | wc -l
259
-
260
- # Usage check
261
- grep -r "User(" src/ | grep -v "models/user.py"
262
- ```
263
-
264
- ### JavaScript/TypeScript
265
- ```bash
266
- # Compilation check (TypeScript)
267
- npx tsc --noEmit
268
-
269
- # Test execution
270
- npm test
271
-
272
- # Import check
273
- grep -r "import.*from.*models/user" src/
274
-
275
- # Usage check
276
- grep -r "new User\|User\.find\|User\.create" src/
277
- ```
278
-
279
- ### Go
280
- ```bash
281
- # Compilation check
282
- go build ./...
283
-
284
- # Test execution
285
- go test ./...
286
-
287
- # Import check
288
- grep -r "\"myapp/models\"" . | wc -l
289
-
290
- # Usage check
291
- grep -r "models\.User" . | grep -v "models/user.go"
292
- ```
293
-
294
- ## Example Verification Report
295
-
296
- A verification report should follow this structure:
297
-
298
- ```markdown
299
- # Verification Report: Phase 01 — Authentication System
300
-
301
- **Status:** Issues Found
302
- **Date:** 2026-03-19
303
- **Plans Verified:** 3
304
-
305
- ## Level 1: Exists ✓
306
-
307
- All expected artifacts are present:
308
- - ✓ src/models/user.rs
309
- - ✓ src/routes/auth.rs
310
- - ✓ src/db/migrations/001_users.sql
311
- - ✓ tests/auth_test.rs
312
-
313
- ## Level 2: Substantive ✓
314
-
315
- All files contain real implementations:
316
- - ✓ User model has 45 lines, includes fields and methods
317
- - ✓ Auth routes have 67 lines, no TODOs
318
- - ✓ Migration file creates users table with all columns
319
- - ✓ Tests have 52 lines with 6 test cases
320
-
321
- ## Level 3: Wired ⚠
322
-
323
- Issues found:
324
- - ⚠ User model is imported by auth routes (OK)
325
- - ⚠ Auth routes use User::new (OK)
326
- - ✗ Registration endpoint returns 500 error
327
- - ✗ No middleware validates session tokens
328
-
329
- ## Gaps
330
-
331
- ```toml
332
- [[gaps]]
333
- truth = "Users can register with email"
334
- status = "failed"
335
- reason = "POST /auth/register returns 500: database connection error"
336
- artifacts = ["src/routes/auth.rs", "src/db/connection.rs"]
337
- missing = ["Database connection pool initialization", "Error handling"]
338
-
339
- [[gaps]]
340
- truth = "Sessions are validated on protected routes"
341
- status = "incomplete"
342
- reason = "Session middleware exists but is not applied to routes"
343
- artifacts = ["src/middleware/session.rs", "src/main.rs"]
344
- missing = ["Apply middleware to protected routes"]
345
- ```
346
-
347
- ## Next Steps
348
-
349
- 1. Run `konductor plan phase 01 --gaps` to create gap-closure plans
350
- 2. Or manually fix: Initialize DB connection pool in main.rs
351
- 3. Re-run verification after fixes
352
- ```
353
-
354
- ## Verification Automation
355
-
356
- Verification should be automated where possible.
357
-
358
- **Pattern: Verification script per plan**
359
-
360
- Create `.konductor/phases/{phase}/verify-plan-{n}.sh`:
361
- ```bash
362
- #!/bin/bash
363
- set -e
364
-
365
- # Level 1: Exists
366
- [ -f src/models/user.rs ] || { echo "FAIL: user.rs missing"; exit 1; }
367
-
368
- # Level 2: Substantive
369
- lines=$(grep -v '^[[:space:]]*//' src/models/user.rs | grep -v '^[[:space:]]*$' | wc -l)
370
- [ "$lines" -gt 20 ] || { echo "FAIL: user.rs is stub"; exit 1; }
371
-
372
- # Level 3: Wired
373
- grep -q "User::" src/routes/auth.rs || { echo "FAIL: User not used in auth"; exit 1; }
374
-
375
- # Truth verification
376
- cargo test auth::test_register || { echo "FAIL: registration test failed"; exit 1; }
377
-
378
- echo "PASS: Plan 1 verified"
379
- ```
380
-
381
- Then run: `bash .konductor/phases/{phase}/verify-plan-{n}.sh`
382
-
383
- ## Verification vs. Testing
384
-
385
- **Testing** checks that code is correct (unit tests, integration tests).
386
- **Verification** checks that execution achieved the phase goal (end-to-end validation).
387
-
388
- **Testing:**
389
- - Runs during execution (per task)
390
- - Checks individual functions
391
- - Passes/fails per test case
392
- - Developer-focused
393
-
394
- **Verification:**
395
- - Runs after all plans execute
396
- - Checks the entire phase
397
- - Validates against must_haves
398
- - User-focused (does it deliver the feature?)
399
-
400
- **Both are necessary.** Tests catch bugs. Verification catches gaps.