@pmelab/gtd 55.0.0 → 56.0.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.
Files changed (61) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +60 -61
  3. package/dist/chunks/{reserved-DHafcW7t.mjs → reserved-B8EC-WE8.mjs} +77 -203
  4. package/dist/chunks/{review-BJGKwlYv.mjs → review-HdrX0FJ7.mjs} +30 -125
  5. package/dist/chunks/{steering-CLhu8C7q.mjs → steering-CCNvngSH.mjs} +256 -65
  6. package/dist/chunks/{tail-B9Hw2AFB.mjs → tail-BSLah2mA.mjs} +144 -56
  7. package/dist/gtd.bundle.mjs +259 -22
  8. package/dist/steering.mjs +2 -2
  9. package/dist/testkit.mjs +6 -6
  10. package/dist/web/main.css +1 -1
  11. package/dist/web/main.js +551 -66
  12. package/dist/workflow-kit.mjs +1 -1
  13. package/dist/workflows/cleanup.mjs +2 -2
  14. package/dist/workflows/feature.mjs +14 -16
  15. package/dist/workflows/fix.mjs +3 -3
  16. package/dist/workflows/review.mjs +3 -3
  17. package/dist/workflows/rollout.mjs +1 -1
  18. package/dist/workflows.mjs +522 -453
  19. package/package.json +1 -1
  20. package/skills/authoring/SKILL.md +3 -3
  21. package/src/cli/Cli.ts +5 -5
  22. package/src/edge/Edge.test.ts +1 -1
  23. package/src/steering/FORMATS.md +5 -1
  24. package/src/steering/SteeringFormats.test.ts +2 -2
  25. package/src/steering/contract.test.ts +1 -0
  26. package/src/steering/findings.test.ts +47 -0
  27. package/src/steering/findings.ts +350 -0
  28. package/src/steering/fixtures/findings/gate.md +34 -0
  29. package/src/steering/fixtures/findings/gate.read.json +87 -0
  30. package/src/steering/index.test.ts +2 -2
  31. package/src/steering/index.ts +4 -3
  32. package/src/steering/review.test.ts +1 -75
  33. package/src/steering/review.ts +1 -74
  34. package/src/workflow/compile.test.ts +1 -0
  35. package/src/workflows/feature/criteria-coverage.feature +1 -6
  36. package/src/workflows/feature/feature.test.ts +1 -1
  37. package/src/workflows/feature/feature.ts +12 -20
  38. package/src/workflows/feature/lens-review.feature +323 -171
  39. package/src/workflows/feature/refactor-absorbs.feature +1 -7
  40. package/src/workflows/feature/refactor-first.feature +2 -10
  41. package/src/workflows/feature/refactor-rebuild.feature +4 -24
  42. package/src/workflows/feature/refactor-review.feature +33 -117
  43. package/src/workflows/feature/refactor.test.ts +0 -2
  44. package/src/workflows/feature/refactor.ts +0 -1
  45. package/src/workflows/feature/review-gate.feature +6 -22
  46. package/src/workflows/feature/reviewer-walkthrough.feature +16 -103
  47. package/src/workflows/feature/standards.feature +75 -34
  48. package/src/workflows/fix/fix-lens-origin.feature +20 -7
  49. package/src/workflows/fix/fix-quality.feature +102 -23
  50. package/src/workflows/review/review-door.feature +62 -59
  51. package/src/workflows/shared/learn.test.ts +0 -14
  52. package/src/workflows/shared/learn.ts +1 -6
  53. package/src/workflows/shared/lenses.ts +149 -43
  54. package/src/workflows/shared/review.test.ts +27 -26
  55. package/src/workflows/shared/review.ts +29 -196
  56. package/src/workflows/shared/tail.ts +18 -9
  57. package/src/workflows/shared/text.test.ts +103 -288
  58. package/src/workflows/shared/text.ts +131 -329
  59. package/src/workflows/feature/review-answers.feature +0 -324
  60. package/src/workflows/feature/severity-budget.feature +0 -116
  61. package/src/workflows/feature/severity-sorted-review.feature +0 -198
@@ -1,11 +1,13 @@
1
1
  @inmem
2
- Feature: the quality lap's findings are triaged before the review
2
+ Feature: the quality lap's findings are triaged, then decided at the finding gate
3
3
 
4
4
  A judge classifies each `## ` finding the lenses wrote to `.gtd/QUALITY.md`:
5
5
  a mechanical one is fixed by the fixer, noise is dropped with its `p` kept in
6
- a trailer, and a design one becomes a note in `.gtd/REVIEW.md`, with answer
7
- boxes, in the chunk the reviewer gave it. gtd lists, without tick boxes,
8
- what was fixed automatically and what was dropped as noise.
6
+ a trailer, and a design one is a note. The notes, then the noise under
7
+ `# Dropped as noise`, rest at the finding gate (`build.quality.gate`), each
8
+ with one `- [ ] fix` box: a ticked finding is fixed, an unticked one
9
+ dropped. The review then walks through the code and lists, in one
10
+ `## Quality lap` chunk, what became of every finding.
9
11
 
10
12
  Background:
11
13
  Given the shipped workflows, as gtd install scaffolds them
@@ -74,14 +76,23 @@ Feature: the quality lap's findings are triaged before the review
74
76
  Should subtract round? The criterion does not say.
75
77
  """
76
78
  And step "build.quality.sorting" runs its script
79
+ And step "build.quality.gating" runs its script
80
+ And step "build.quality.picking" runs its script
77
81
  And step "build.quality.closing" runs its script
78
82
  And step "build.review.carrying" runs its script
79
- And judge step "build.review.ranking" answers:
83
+ And step "build.health.check" changes nothing
84
+ And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
80
85
  """
81
- []
86
+ # Review: abc1234
87
+
88
+ <!-- base: 0000000 -->
89
+
90
+ ## Subtract
91
+
92
+ - [ ] ./src/calc.ts#2-2 — subtract(a, b)
82
93
  """
83
94
 
84
- Scenario: a mechanical finding is fixed and listed, noise dropped and listed, a design one noted
95
+ Scenario: a mechanical finding is fixed, the rest wait at the finding gate, and an untouched gate drops them
85
96
  Given judge step "build.quality.triage" answers:
86
97
  """
87
98
  [{"id":"Q1","answer":"mechanical","p":0.9},{"id":"Q2","answer":"noise","p":0.85},{"id":"Q3","answer":"design","p":0.8}]
@@ -92,62 +103,56 @@ Feature: the quality lap's findings are triaged before the review
92
103
  it("subtracts a larger number", () => {})
93
104
  """
94
105
  And step "build.fix.quality.fixing" deletes ".gtd/QUALITY.md"
95
- And step "build.health.check" changes nothing
96
- And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
97
- """
98
- # Review: abc1234
99
-
100
- <!-- base: 0000000 -->
101
-
102
- ## Subtract
103
-
104
- - [ ] ./src/calc.ts#2-2 — subtract(a, b)
105
-
106
- ## AC-1 ignores floating point
107
-
108
- - [ ] ./src/calc.ts#2-2 — where it applies
109
- """
110
106
  When the process is driven
111
- Then the process rests at "build.review.await-review"
112
- And ".gtd/QUALITY.md" does not exist
107
+ Then the process rests at "build.quality.gate"
113
108
  And the commit "gtd(judge): build.quality.triage → build.quality.sorting" has a body containing "Gtd-Mark: noise=Q2 p=0.85 add could be a method"
114
- And ".gtd/REVIEW.md" contains:
109
+ And ".gtd/QUALITY.md" contains:
115
110
  """
116
- ## Findings
117
-
118
- ### AC-1 ignores floating point
111
+ ## AC-1 ignores floating point
119
112
 
120
- _critical: judge unsure_
113
+ _From lens correctness._
121
114
 
122
115
  Should subtract round? The criterion does not say.
123
116
 
124
- In the code:
117
+ - [ ] fix
125
118
 
126
- - [ ] ./src/calc.ts#2-2 — where it applies
119
+ # Dropped as noise
127
120
 
128
- Tick exactly one:
121
+ ## add could be a method
129
122
 
130
- - [ ] fix as suggested
131
- - [ ] won't fix
132
- - [ ] _your answer_
123
+ _From lens correctness. The judge called it noise (p=0.85)._
133
124
 
134
- ## Walkthrough
125
+ A class would read better.
135
126
 
136
- ### Subtract
127
+ - [ ] fix
137
128
  """
138
- And ".gtd/REVIEW.md" contains the short hash of the commit "gtd(agent): build.fix.quality.fixing → build.health.check"
129
+ When gtd lands
130
+ And the process is driven
131
+ Then the process rests at "build.review.await-review"
132
+ And ".gtd/QUALITY.md" does not exist
139
133
  And ".gtd/REVIEW.md" contains:
140
134
  """
141
- ## Dropped as noise
135
+ ## Quality lap
136
+
137
+ What the quality lenses found, and what became of it. Write a note under
138
+ a line to reopen it.
142
139
 
143
- - add could be a method (p=0.85)
140
+ Fixed automatically:
141
+
142
+ - subtract has no negative test (
144
143
  """
145
144
  And ".gtd/REVIEW.md" contains:
146
145
  """
147
- ## Fixed automatically
146
+ Dropped at the finding gate:
148
147
 
149
- - subtract has no negative test (
148
+ - AC-1 ignores floating point (lens correctness)
149
+
150
+ Dropped as noise:
151
+
152
+ - add could be a method (p=0.85, lens correctness)
150
153
  """
154
+ And ".gtd/REVIEW.md" contains the short hash of the commit "gtd(agent): build.fix.quality.fixing → build.health.check"
155
+ And ".gtd/REVIEW.md" does not contain "Tick exactly one:"
151
156
  And the commit subjects end with:
152
157
  """
153
158
  gtd(check): implement.closing → build.quality.correctness.reviewing
@@ -155,175 +160,228 @@ Feature: the quality lap's findings are triaged before the review
155
160
  gtd(judge): build.quality.triage → build.quality.sorting
156
161
  gtd(check): build.quality.sorting → build.fix.quality.fixing
157
162
  gtd(agent): build.fix.quality.fixing → build.health.check
158
- gtd(check): build.health.check → build.review.reviewing
159
- gtd(agent): build.review.reviewing → build.review.ranking
160
- gtd(judge): build.review.ranking → build.review.carrying
163
+ gtd(check): build.health.check → build.quality.gating
164
+ gtd(check): build.quality.gating → build.quality.gate
165
+ gtd(human): build.quality.gate → build.quality.closing
166
+ gtd(check): build.quality.closing → build.review.reviewing
167
+ gtd(agent): build.review.reviewing → build.review.carrying
161
168
  gtd(check): build.review.carrying → build.review.await-review
162
169
  """
163
170
 
164
- Scenario: a risk is fixed before the human sees the review, re-reviewed in the reviewer's own draft
171
+ Scenario: a ticked note is fixed with the human's guidance, never re-planned
165
172
  Given judge step "build.quality.triage" answers:
166
173
  """
167
- [{"id":"Q1","answer":"mechanical","p":0.9},{"id":"Q2","answer":"noise","p":0.85},{"id":"Q3","answer":"design","p":0.8}]
168
- """
169
- And step "build.fix.quality.fixing" writes "src/calc.test.ts" with:
174
+ [{"id":"Q1","answer":"noise","p":0.9},{"id":"Q2","answer":"noise","p":0.85},{"id":"Q3","answer":"design","p":0.8}]
170
175
  """
171
- it("[AC-1] subtracts", () => {})
172
- it("subtracts a larger number", () => {})
173
- """
174
- And step "build.fix.quality.fixing" deletes ".gtd/QUALITY.md"
175
- And step "build.health.check" changes nothing
176
- And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
176
+ When the process is driven
177
+ Then the process rests at "build.quality.gate"
178
+ Given a file ".gtd/QUALITY.md" with:
177
179
  """
178
- # Review: abc1234
180
+ # Quality
179
181
 
180
- <!-- base: 0000000 -->
182
+ ## AC-1 ignores floating point
181
183
 
182
- ## Subtract
184
+ _From lens correctness._
183
185
 
184
- - [ ] ./src/calc.ts#2-2 — Risk: overflows on large numbers
186
+ Should subtract round? The criterion does not say.
187
+
188
+ - [x] fix
189
+
190
+ Round half up.
191
+
192
+ # Dropped as noise
193
+
194
+ ## subtract has no negative test
195
+
196
+ _From lens correctness. The judge called it noise (p=0.9)._
197
+
198
+ Add a test subtracting a larger number.
199
+
200
+ - [ ] fix
201
+
202
+ ## add could be a method
203
+
204
+ _From lens correctness. The judge called it noise (p=0.85)._
205
+
206
+ A class would read better.
185
207
 
208
+ - [ ] fix
209
+ """
210
+ When gtd lands
211
+ And the process is driven
212
+ Then the process rests at "build.fix.quality.fixing"
213
+ And ".gtd/QUALITY.md" contains:
214
+ """
186
215
  ## AC-1 ignores floating point
187
216
 
188
- - [ ] ./src/calc.ts#2-2 — where it applies
217
+ Should subtract round? The criterion does not say.
218
+
219
+ Guidance from the human — follow it:
220
+
221
+ Round half up.
189
222
  """
190
- When the process is driven
191
- Then the process rests at "build.review.fix.risks.fixing"
192
- Given step "build.review.reviewing" is no longer scripted
193
- And step "build.review.reviewing" replaces the text "Risk: overflows on large numbers" in ".gtd/REVIEW.md" with "subtract(a, b), now guarded"
194
- And step "build.review.fix.risks.fixing" changes nothing
223
+ And ".gtd/QUALITY.md" does not contain "add could be a method"
224
+ Given step "build.fix.quality.fixing" writes "src/calc.ts" with:
225
+ """
226
+ export const add = (a: number, b: number) => a + b
227
+ export const subtract = (a: number, b: number) => Math.round(a - b)
228
+ """
229
+ And step "build.fix.quality.fixing" deletes ".gtd/QUALITY.md"
195
230
  When the process is driven
196
231
  Then the process rests at "build.review.await-review"
197
- And ".gtd/REVIEW.md" contains "subtract(a, b), now guarded"
198
- And ".gtd/REVIEW.md" contains "## Fixed automatically" exactly once
199
- And ".gtd/REVIEW.md" contains "## Dropped as noise" exactly once
200
- And ".gtd/REVIEW.md" contains "## Walkthrough" exactly once
201
- And ".gtd/REVIEW.md" contains "Should subtract round? The criterion does not say." exactly once
202
- And ".gtd/REVIEW.md" contains "Tick exactly one:" exactly once
232
+ And ".gtd/REVIEW.md" contains:
233
+ """
234
+ Fixed at the finding gate:
235
+
236
+ - AC-1 ignores floating point (
237
+ """
238
+ And ".gtd/REVIEW.md" contains:
239
+ """
240
+ Dropped as noise:
241
+
242
+ - subtract has no negative test (p=0.9, lens correctness)
243
+ - add could be a method (p=0.85, lens correctness)
244
+ """
203
245
  And the commit subjects end with:
204
246
  """
247
+ gtd(human): build.quality.gate → build.quality.picking
248
+ gtd(check): build.quality.picking → build.fix.quality.fixing
249
+ gtd(agent): build.fix.quality.fixing → build.health.check
205
250
  gtd(check): build.health.check → build.review.reviewing
206
- gtd(agent): build.review.reviewing → build.review.fix.risks.fixing
207
- gtd(agent): build.review.fix.risks.fixing → build.health.check
208
- gtd(check): build.health.check → build.review.reviewing
209
- gtd(agent): build.review.reviewing → build.review.ranking
210
- gtd(judge): build.review.ranking → build.review.carrying
251
+ gtd(agent): build.review.reviewing → build.review.carrying
211
252
  gtd(check): build.review.carrying → build.review.await-review
212
253
  """
213
254
 
214
- Scenario: an unsure verdict makes a finding a note, never a fix or a drop
255
+ Scenario: a finding the judge called noise is rescued by its tick
215
256
  Given judge step "build.quality.triage" answers:
216
257
  """
217
- [{"id":"Q1","answer":"mechanical","p":0.5},{"id":"Q2","answer":"noise","p":0.6}]
258
+ [{"id":"Q1","answer":"noise","p":0.9},{"id":"Q2","answer":"noise","p":0.85},{"id":"Q3","answer":"noise","p":0.8}]
218
259
  """
219
- And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
260
+ And step "build.fix.quality.fixing" deletes ".gtd/QUALITY.md"
261
+ When the process is driven
262
+ Then the process rests at "build.quality.gate"
263
+ Given a file ".gtd/QUALITY.md" with:
220
264
  """
221
- # Review: abc1234
222
-
223
- <!-- base: 0000000 -->
224
-
225
- ## Subtract
265
+ # Quality
226
266
 
227
- - [ ] ./src/calc.ts#2-2 — subtract(a, b)
267
+ # Dropped as noise
228
268
 
229
269
  ## subtract has no negative test
230
270
 
231
- - [ ] ./src/calc.ts#2-2 — where it applies
271
+ Add a test subtracting a larger number.
272
+
273
+ - [ ] fix
232
274
 
233
275
  ## add could be a method
234
276
 
235
- - [ ] ./src/calc.ts#2-2 — where it applies
277
+ A class would read better.
278
+
279
+ - [x] fix
236
280
 
237
281
  ## AC-1 ignores floating point
238
282
 
239
- - [ ] ./src/calc.ts#2-2 — where it applies
283
+ Should subtract round? The criterion does not say.
284
+
285
+ - [ ] fix
240
286
  """
241
- When the process is driven
287
+ When gtd lands
288
+ And the process is driven
242
289
  Then the process rests at "build.review.await-review"
243
- And ".gtd/REVIEW.md" contains "## subtract has no negative test"
244
- And ".gtd/REVIEW.md" contains "## add could be a method"
245
- And ".gtd/REVIEW.md" contains "## AC-1 ignores floating point"
246
- And ".gtd/REVIEW.md" does not contain "Fixed automatically"
247
- And no commit body contains "Gtd-Mark: noise="
248
- And the commit subjects end with:
290
+ And ".gtd/REVIEW.md" contains:
249
291
  """
250
- gtd(judge): build.quality.triage → build.quality.sorting
251
- gtd(check): build.quality.sorting → build.review.reviewing
252
- gtd(agent): build.review.reviewing → build.review.ranking
253
- gtd(judge): build.review.ranking → build.review.carrying
254
- gtd(check): build.review.carrying → build.review.await-review
292
+ Fixed at the finding gate:
293
+
294
+ - add could be a method (
295
+ """
296
+ And ".gtd/REVIEW.md" contains:
297
+ """
298
+ Dropped as noise:
299
+
300
+ - subtract has no negative test (p=0.9, lens correctness)
301
+ - AC-1 ignores floating point (p=0.8, lens correctness)
255
302
  """
256
303
 
257
- Scenario: a mechanical finding the fix cap leaves becomes a note
304
+ Scenario: guidance under an unticked box is refused
258
305
  Given judge step "build.quality.triage" answers:
259
306
  """
260
- [{"id":"Q1","answer":"mechanical","p":0.9},{"id":"Q2","answer":"mechanical","p":0.9},{"id":"Q3","answer":"mechanical","p":0.9}]
307
+ [{"id":"Q1","answer":"noise","p":0.9},{"id":"Q2","answer":"noise","p":0.85},{"id":"Q3","answer":"design","p":0.8}]
261
308
  """
262
- And step "build.fix.quality.fixing" writes ".gtd/QUALITY.md" with:
309
+ When the process is driven
310
+ Then the process rests at "build.quality.gate"
311
+ Given a file ".gtd/QUALITY.md" with:
263
312
  """
264
313
  # Quality
265
314
 
266
- ## add could be a method
315
+ ## AC-1 ignores floating point
267
316
 
268
- A class would read better.
269
- """
270
- And step "build.health.check" changes nothing
271
- And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
272
- """
273
- # Review: abc1234
317
+ Should subtract round? The criterion does not say.
274
318
 
275
- <!-- base: 0000000 -->
319
+ - [ ] fix
276
320
 
277
- ## Subtract
321
+ Round half up.
322
+ """
323
+ Then landing is refused with "finding-gate: 1 problem(s) in .gtd/QUALITY.md"
324
+ And landing is refused with "has guidance under an unticked box — tick it to fix the finding, or delete the text to drop it"
278
325
 
279
- - [ ] ./src/calc.ts#2-2 — subtract(a, b)
326
+ Scenario: a ticked finding the fix cap leaves is listed unresolved, with no second gate
327
+ Given judge step "build.quality.triage" answers:
328
+ """
329
+ [{"id":"Q1","answer":"noise","p":0.9},{"id":"Q2","answer":"noise","p":0.85},{"id":"Q3","answer":"design","p":0.8}]
330
+ """
331
+ And step "build.fix.quality.fixing" changes nothing
332
+ When the process is driven
333
+ Then the process rests at "build.quality.gate"
334
+ Given a file ".gtd/QUALITY.md" with:
335
+ """
336
+ # Quality
280
337
 
281
- ## add could be a method
338
+ ## AC-1 ignores floating point
339
+
340
+ Should subtract round? The criterion does not say.
282
341
 
283
- - [ ] ./src/calc.ts#2-2 — where it applies
342
+ - [x] fix
284
343
  """
285
- When the process is driven
344
+ When gtd lands
345
+ And the process is driven
286
346
  Then the process rests at "build.review.await-review"
287
347
  And ".gtd/QUALITY.md" does not exist
288
348
  And ".gtd/REVIEW.md" contains:
289
349
  """
290
- ### add could be a method
291
-
292
- _critical: judge unsure_
293
-
294
- _The fixer left this unresolved._
350
+ Unresolved after the finding gate:
295
351
 
296
- A class would read better.
352
+ - AC-1 ignores floating point (lens correctness)
297
353
  """
298
- And ".gtd/REVIEW.md" contains "- subtract has no negative test ("
299
- And ".gtd/REVIEW.md" contains "- AC-1 ignores floating point ("
300
354
  And the commit subjects end with:
301
355
  """
302
- gtd(judge): build.quality.triage → build.fix.quality.fixing
356
+ gtd(human): build.quality.gate → build.quality.picking
357
+ gtd(check): build.quality.picking → build.fix.quality.fixing
303
358
  gtd(agent): build.fix.quality.fixing
304
359
  gtd(agent): build.fix.quality.fixing
305
360
  gtd(agent): build.fix.quality.fixing → build.health.check
306
361
  gtd(check): build.health.check → build.quality.closing
307
362
  gtd(check): build.quality.closing → build.review.reviewing
308
- gtd(agent): build.review.reviewing → build.review.ranking
309
- gtd(judge): build.review.ranking → build.review.carrying
363
+ gtd(agent): build.review.reviewing → build.review.carrying
310
364
  gtd(check): build.review.carrying → build.review.await-review
311
365
  """
312
366
 
313
- Scenario: a fixer that renames a chunk it leaves counts nothing fixed
367
+ Scenario: a lap whose every finding was fixed has no gate
314
368
  Given judge step "build.quality.triage" answers:
315
369
  """
316
370
  [{"id":"Q1","answer":"mechanical","p":0.9},{"id":"Q2","answer":"mechanical","p":0.9},{"id":"Q3","answer":"mechanical","p":0.9}]
317
371
  """
318
- And step "build.fix.quality.fixing" writes ".gtd/QUALITY.md" with:
319
- """
320
- # Quality
321
-
322
- ## null check in parse()
372
+ And step "build.fix.quality.fixing" deletes ".gtd/QUALITY.md"
373
+ When the process is driven
374
+ Then the process rests at "build.review.await-review"
375
+ And no commit body contains "build.quality.gate"
376
+ And ".gtd/REVIEW.md" contains "- AC-1 ignores floating point ("
323
377
 
324
- Still open.
378
+ Scenario: a risk is fixed before the human sees the review, re-reviewed in the reviewer's own draft
379
+ Given judge step "build.quality.triage" answers:
325
380
  """
326
- And step "build.health.check" changes nothing
381
+ [{"id":"Q1","answer":"mechanical","p":0.9},{"id":"Q2","answer":"noise","p":0.85},{"id":"Q3","answer":"design","p":0.8}]
382
+ """
383
+ And step "build.fix.quality.fixing" deletes ".gtd/QUALITY.md"
384
+ And step "build.quality.gate" changes nothing
327
385
  And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
328
386
  """
329
387
  # Review: abc1234
@@ -332,30 +390,111 @@ Feature: the quality lap's findings are triaged before the review
332
390
 
333
391
  ## Subtract
334
392
 
335
- - [ ] ./src/calc.ts#2-2 — subtract(a, b)
393
+ - [ ] ./src/calc.ts#2-2 — Risk: overflows on large numbers
394
+ """
395
+ When the process is driven
396
+ Then the process rests at "build.review.fix.risks.fixing"
397
+ And ".gtd/REVIEW.md" does not contain "## Quality lap"
398
+ Given step "build.review.reviewing" is no longer scripted
399
+ And step "build.review.reviewing" replaces the text "Risk: overflows on large numbers" in ".gtd/REVIEW.md" with "subtract(a, b), now guarded"
400
+ And step "build.review.fix.risks.fixing" changes nothing
401
+ When the process is driven
402
+ Then the process rests at "build.review.await-review"
403
+ And ".gtd/REVIEW.md" contains "subtract(a, b), now guarded"
404
+ And ".gtd/REVIEW.md" contains "## Quality lap" exactly once
405
+ And ".gtd/REVIEW.md" contains "Fixed automatically:" exactly once
406
+ And the commit subjects end with:
407
+ """
408
+ gtd(check): build.quality.closing → build.review.reviewing
409
+ gtd(agent): build.review.reviewing → build.review.fix.risks.fixing
410
+ gtd(agent): build.review.fix.risks.fixing → build.health.check
411
+ gtd(check): build.health.check → build.review.reviewing
412
+ gtd(agent): build.review.reviewing → build.review.carrying
413
+ gtd(check): build.review.carrying → build.review.await-review
414
+ """
336
415
 
337
- ## subtract has no negative test
416
+ Scenario: an unsure verdict makes a finding a note, never a fix or a drop
417
+ Given judge step "build.quality.triage" answers:
418
+ """
419
+ [{"id":"Q1","answer":"mechanical","p":0.5},{"id":"Q2","answer":"noise","p":0.6}]
420
+ """
421
+ When the process is driven
422
+ Then the process rests at "build.quality.gate"
423
+ And ".gtd/QUALITY.md" contains "## subtract has no negative test"
424
+ And ".gtd/QUALITY.md" contains "## add could be a method"
425
+ And ".gtd/QUALITY.md" contains "## AC-1 ignores floating point"
426
+ And ".gtd/QUALITY.md" does not contain "# Dropped as noise"
427
+ And no commit body contains "Gtd-Mark: noise="
428
+ And the commit subjects end with:
429
+ """
430
+ gtd(agent): build.quality.correctness.reviewing → build.quality.triage
431
+ gtd(judge): build.quality.triage → build.quality.gating
432
+ gtd(check): build.quality.gating → build.quality.gate
433
+ """
338
434
 
339
- - [ ] ./src/calc.ts#2-2 — where it applies
435
+ Scenario: a mechanical finding the fix cap leaves reaches the gate as unresolved
436
+ Given judge step "build.quality.triage" answers:
437
+ """
438
+ [{"id":"Q1","answer":"mechanical","p":0.9},{"id":"Q2","answer":"mechanical","p":0.9},{"id":"Q3","answer":"mechanical","p":0.9}]
439
+ """
440
+ And step "build.fix.quality.fixing" writes ".gtd/QUALITY.md" with:
441
+ """
442
+ # Quality
340
443
 
341
444
  ## add could be a method
342
445
 
343
- - [ ] ./src/calc.ts#2-2 — where it applies
446
+ A class would read better.
447
+ """
448
+ When the process is driven
449
+ Then the process rests at "build.quality.gate"
450
+ And ".gtd/QUALITY.md" contains:
451
+ """
452
+ ## add could be a method
344
453
 
345
- ## AC-1 ignores floating point
454
+ _From lens correctness. The fixer left it unresolved._
455
+
456
+ A class would read better.
457
+
458
+ - [ ] fix
459
+ """
460
+ And the commit subjects end with:
461
+ """
462
+ gtd(judge): build.quality.triage → build.fix.quality.fixing
463
+ gtd(agent): build.fix.quality.fixing
464
+ gtd(agent): build.fix.quality.fixing
465
+ gtd(agent): build.fix.quality.fixing → build.health.check
466
+ gtd(check): build.health.check → build.quality.gating
467
+ gtd(check): build.quality.gating → build.quality.gate
468
+ """
469
+ When gtd lands
470
+ And the process is driven
471
+ Then the process rests at "build.review.await-review"
472
+ And ".gtd/REVIEW.md" contains "- subtract has no negative test ("
473
+ And ".gtd/REVIEW.md" contains:
474
+ """
475
+ Dropped at the finding gate:
346
476
 
347
- - [ ] ./src/calc.ts#2-2 — where it applies
477
+ - add could be a method (lens correctness)
478
+ """
479
+
480
+ Scenario: a fixer that renames a chunk it leaves counts nothing fixed
481
+ Given judge step "build.quality.triage" answers:
482
+ """
483
+ [{"id":"Q1","answer":"mechanical","p":0.9},{"id":"Q2","answer":"mechanical","p":0.9},{"id":"Q3","answer":"mechanical","p":0.9}]
484
+ """
485
+ And step "build.fix.quality.fixing" writes ".gtd/QUALITY.md" with:
486
+ """
487
+ # Quality
348
488
 
349
489
  ## null check in parse()
350
490
 
351
- - [ ] ./src/calc.ts#2-2 — where it applies
491
+ Still open.
352
492
  """
353
493
  When the process is driven
354
- Then the process rests at "build.review.await-review"
355
- And ".gtd/REVIEW.md" contains "## null check in parse()"
356
- And ".gtd/REVIEW.md" contains "## subtract has no negative test"
357
- And ".gtd/REVIEW.md" contains "check whether it was fixed"
358
- And ".gtd/REVIEW.md" does not contain "Fixed automatically"
494
+ Then the process rests at "build.quality.gate"
495
+ And ".gtd/QUALITY.md" contains "## null check in parse()"
496
+ And ".gtd/QUALITY.md" contains "## subtract has no negative test"
497
+ And ".gtd/QUALITY.md" contains "check whether it was fixed"
359
498
 
360
499
  Scenario: prose the fixer leaves outside every chunk does not hide its fixes
361
500
  Given judge step "build.quality.triage" answers:
@@ -368,38 +507,18 @@ Feature: the quality lap's findings are triaged before the review
368
507
 
369
508
  All fixed.
370
509
  """
371
- And step "build.health.check" changes nothing
372
- And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
373
- """
374
- # Review: abc1234
375
-
376
- <!-- base: 0000000 -->
377
-
378
- ## Subtract
379
-
380
- - [ ] ./src/calc.ts#2-2 — subtract(a, b)
381
- """
382
510
  When the process is driven
383
511
  Then the process rests at "build.review.await-review"
384
512
  And ".gtd/REVIEW.md" contains "- subtract has no negative test ("
385
513
  And ".gtd/REVIEW.md" does not contain "check whether it was fixed"
386
514
 
387
- Scenario: signing off a review with no notes ends the process
515
+ Scenario: signing off the review ends the process
388
516
  Given judge step "build.quality.triage" answers:
389
517
  """
390
518
  [{"id":"Q1","answer":"noise","p":0.9},{"id":"Q2","answer":"noise","p":0.9},{"id":"Q3","answer":"noise","p":0.9}]
391
519
  """
520
+ And step "build.quality.gate" changes nothing
392
521
  And step "build.review.closing" runs its script
393
- And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
394
- """
395
- # Review: abc1234
396
-
397
- <!-- base: 0000000 -->
398
-
399
- ## Subtract
400
-
401
- - [ ] ./src/calc.ts#2-2 — subtract(a, b)
402
- """
403
522
  When the process is driven
404
523
  Then the process rests at "build.review.await-review"
405
524
  When gtd lands
@@ -408,9 +527,42 @@ Feature: the quality lap's findings are triaged before the review
408
527
  And ".gtd/REVIEW.md" does not exist
409
528
  And the commit subjects end with:
410
529
  """
411
- gtd(agent): build.review.reviewing → build.review.ranking
412
- gtd(judge): build.review.ranking → build.review.carrying
530
+ gtd(agent): build.review.reviewing → build.review.carrying
413
531
  gtd(check): build.review.carrying → build.review.await-review
414
532
  gtd(human): build.review.await-review → build.review.closing
415
533
  gtd(check): build.review.closing → idle
416
534
  """
535
+
536
+ Scenario: a finding whose entry the human deleted is listed as dropped
537
+ Given judge step "build.quality.triage" answers:
538
+ """
539
+ [{"id":"Q1","answer":"noise","p":0.9},{"id":"Q2","answer":"noise","p":0.85},{"id":"Q3","answer":"design","p":0.8}]
540
+ """
541
+ When the process is driven
542
+ Then the process rests at "build.quality.gate"
543
+ Given a file ".gtd/QUALITY.md" with:
544
+ """
545
+ # Quality
546
+
547
+ # Dropped as noise
548
+
549
+ ## add could be a method
550
+
551
+ A class would read better.
552
+
553
+ - [ ] fix
554
+ """
555
+ When gtd lands
556
+ And the process is driven
557
+ Then the process rests at "build.review.await-review"
558
+ And ".gtd/REVIEW.md" contains:
559
+ """
560
+ Dropped at the finding gate:
561
+
562
+ - AC-1 ignores floating point (lens correctness)
563
+
564
+ Dropped as noise:
565
+
566
+ - add could be a method (p=0.85, lens correctness)
567
+ - subtract has no negative test (p=0.9, lens correctness)
568
+ """