@pmelab/gtd 28.2.0 → 29.1.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 (53) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +28 -14
  3. package/claude/hooks/handoff.ts +2 -3
  4. package/claude/hooks/ship.ts +762 -62
  5. package/dist/chunks/{reserved-DeBS4Ymh.mjs → reserved-DoHUII2D.mjs} +206 -121
  6. package/dist/chunks/{tail-B2SER2Ih.mjs → tail-C6YBG5zh.mjs} +19 -12
  7. package/dist/testkit.mjs +2 -1
  8. package/dist/workflow-kit.mjs +51 -21
  9. package/dist/workflows/cleanup.mjs +2 -2
  10. package/dist/workflows/feature.mjs +247 -96
  11. package/dist/workflows/fix.mjs +2 -2
  12. package/dist/workflows/review.mjs +2 -2
  13. package/dist/workflows/rollout.mjs +1 -1
  14. package/dist/workflows.mjs +528 -262
  15. package/package.json +1 -1
  16. package/src/testkit/TestRepo.ts +3 -0
  17. package/src/testkit/index.ts +1 -1
  18. package/src/testkit/steps.ts +44 -0
  19. package/src/workflow-kit/review.test.ts +366 -8
  20. package/src/workflow-kit/review.ts +109 -26
  21. package/src/workflows/feature/feature.test.ts +313 -1
  22. package/src/workflows/feature/feature.ts +48 -43
  23. package/src/workflows/feature/one-step-land.feature +4 -0
  24. package/src/workflows/feature/refactor-first.feature +54 -24
  25. package/src/workflows/feature/refactor-review.feature +1706 -0
  26. package/src/workflows/feature/refactor.test.ts +592 -2
  27. package/src/workflows/feature/refactor.ts +160 -42
  28. package/src/workflows/feature/review.test.ts +322 -5
  29. package/src/workflows/feature/review.ts +77 -10
  30. package/src/workflows/feature/seam-rejection.feature +4 -0
  31. package/src/workflows/feature/seam.feature +3 -4
  32. package/src/workflows/feature/seam.test.ts +196 -1
  33. package/src/workflows/feature/seam.ts +23 -9
  34. package/src/workflows/feature/steps.test.ts +54 -2
  35. package/src/workflows/feature/steps.ts +45 -9
  36. package/src/workflows/feature/tier.test.ts +4 -0
  37. package/src/workflows/feature/tier.ts +2 -20
  38. package/src/workflows/shared/__fixtures__/feature-collecting-prompt.txt +97 -0
  39. package/src/workflows/shared/access.test.ts +31 -1
  40. package/src/workflows/shared/access.ts +7 -1
  41. package/src/workflows/shared/fences.ts +19 -0
  42. package/src/workflows/shared/health.ts +32 -12
  43. package/src/workflows/shared/options.test.ts +18 -0
  44. package/src/workflows/shared/options.ts +1 -0
  45. package/src/workflows/shared/prose.ts +4 -2
  46. package/src/workflows/shared/skills.test.ts +20 -1
  47. package/src/workflows/shared/skills.ts +43 -32
  48. package/src/workflows/shared/steps.ts +33 -19
  49. package/src/workflows/shared/tail.test.ts +84 -1
  50. package/src/workflows/shared/tail.ts +30 -12
  51. package/src/workflows/shared/text.test.ts +266 -3
  52. package/src/workflows/shared/text.ts +183 -69
  53. package/src/workflows/shared/vars.ts +12 -2
@@ -0,0 +1,1706 @@
1
+ @inmem
2
+ Feature: the refactor slice is reviewed on its own before the feature is implemented
3
+
4
+ After a refactor-first judgment the refactor is built, quality-lapped and
5
+ reviewed in its own slice. Review edits re-run the refactor, never the design;
6
+ the feature review that follows covers only what came after the refactor's
7
+ sign-off. The flags are pinned so the per-flag test runs never move it off
8
+ its path.
9
+
10
+ Background:
11
+ Given the shipped workflows, as gtd install scaffolds them
12
+ And an environment variable "GTD_QUALITYREVIEWS" set to ""
13
+ And an environment variable "GTD_FLAG_NAIVE_PASS" set to "1"
14
+ And an environment variable "GTD_FLAG_RISK_TIER" set to "0"
15
+
16
+ Scenario: with a narrowed seamAllow a test-named file written by the refactor is refused
17
+ Given an environment variable "GTD_REFACTORQUALITYREVIEWS" set to ""
18
+ And an environment variable "GTD_SEAMALLOW" set to "docs/**"
19
+ And a file "src/calc.ts" with:
20
+ """
21
+ export const add = (a: number, b: number) => a + b
22
+ """
23
+ And a file "src/calc.test.ts" with:
24
+ """
25
+ import { expect, it } from "vitest"
26
+ it("adds", () => expect(1 + 1).toBe(2))
27
+ """
28
+ And a file "src/*.ts" with:
29
+ """
30
+ export const literalGlobName = 1
31
+ """
32
+ And the working tree is committed as "feat: add calculator"
33
+ And a file "TODO.md" with:
34
+ """
35
+ # Add subtract
36
+
37
+ subtract(a, b) returns the difference.
38
+ """
39
+ And step "unwind" changes nothing
40
+ And step "start-gate.check" changes nothing
41
+ And step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
42
+ """
43
+ # Requirements
44
+
45
+ ## Concerns
46
+
47
+ ### Subtract
48
+
49
+ - `subtract(a, b)` returns `a - b`.
50
+ """
51
+ And step "design.gate.answer" changes nothing
52
+ And step "seam.naive" writes "src/calc.ts" with:
53
+ """
54
+ export const add = (a: number, b: number) => a + b
55
+ export const subtract = (a: number, b: number) => a - b
56
+ """
57
+ And judge step "seam.judge" answers:
58
+ """
59
+ [{"id":"shape","answer":"refactor-first","p":0.9}]
60
+ """
61
+ And step "refactor.deriving" runs its script
62
+ And step "refactor.building" writes "src/calc.ts" with:
63
+ """
64
+ export const op = (a: number, b: number, sign: number) => a + sign * b
65
+ export const add = (a: number, b: number) => op(a, b, 1)
66
+ """
67
+ And step "refactor.health.check" changes nothing
68
+ And step "refactor.closing" runs its script
69
+ And step "refactor.build.review.reviewing" writes ".gtd/REVIEW.md" with:
70
+ """
71
+ # Review: abc1234
72
+
73
+ <!-- base: 0000000 -->
74
+
75
+ ## calc
76
+
77
+ - [ ] ./src/calc.ts#1-2
78
+ add built on the shared op
79
+ """
80
+ And step "refactor.build.review.closing" runs its script
81
+
82
+
83
+ And step "seam.naive" writes "src/calc.test.ts" with:
84
+ """
85
+ import { expect, it } from "vitest"
86
+ it("adds", () => expect(2 + 2).toBe(4))
87
+ """
88
+ And step "refactor.building" writes "src/calc.test.ts" with:
89
+ """
90
+ import { expect, it } from "vitest"
91
+ it("adds", () => expect(3 + 3).toBe(6))
92
+ """
93
+ Then driving the process is refused with "outside its write access"
94
+
95
+
96
+ Scenario: refactorQualityReviews picks the refactor's lenses and qualityReviews does not reach them
97
+ Given an environment variable "GTD_REFACTORQUALITYREVIEWS" set to "correctness"
98
+ And an environment variable "GTD_QUALITYREVIEWS" set to "owasp-security"
99
+ And a file "src/calc.ts" with:
100
+ """
101
+ export const add = (a: number, b: number) => a + b
102
+ """
103
+ And a file "src/calc.test.ts" with:
104
+ """
105
+ import { expect, it } from "vitest"
106
+ it("adds", () => expect(1 + 1).toBe(2))
107
+ """
108
+ And a file "src/*.ts" with:
109
+ """
110
+ export const literalGlobName = 1
111
+ """
112
+ And the working tree is committed as "feat: add calculator"
113
+ And a file "TODO.md" with:
114
+ """
115
+ # Add subtract
116
+
117
+ subtract(a, b) returns the difference.
118
+ """
119
+ And step "unwind" changes nothing
120
+ And step "start-gate.check" changes nothing
121
+ And step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
122
+ """
123
+ # Requirements
124
+
125
+ ## Concerns
126
+
127
+ ### Subtract
128
+
129
+ - `subtract(a, b)` returns `a - b`.
130
+ """
131
+ And step "design.gate.answer" changes nothing
132
+ And step "seam.naive" writes "src/calc.ts" with:
133
+ """
134
+ export const add = (a: number, b: number) => a + b
135
+ export const subtract = (a: number, b: number) => a - b
136
+ """
137
+ And judge step "seam.judge" answers:
138
+ """
139
+ [{"id":"shape","answer":"refactor-first","p":0.9}]
140
+ """
141
+ And step "refactor.deriving" runs its script
142
+ And step "refactor.building" writes "src/calc.ts" with:
143
+ """
144
+ export const op = (a: number, b: number, sign: number) => a + sign * b
145
+ export const add = (a: number, b: number) => op(a, b, 1)
146
+ """
147
+ And step "refactor.health.check" changes nothing
148
+ And step "refactor.closing" runs its script
149
+ And step "refactor.build.review.reviewing" writes ".gtd/REVIEW.md" with:
150
+ """
151
+ # Review: abc1234
152
+
153
+ <!-- base: 0000000 -->
154
+
155
+ ## calc
156
+
157
+ - [ ] ./src/calc.ts#1-2
158
+ add built on the shared op
159
+ """
160
+ And step "refactor.build.review.closing" runs its script
161
+
162
+
163
+ And step "refactor.build.quality.correctness.reviewing" changes nothing
164
+ When the process is driven
165
+ Then the process rests at "refactor.build.review.await-review"
166
+ And the commit subjects end with:
167
+ """
168
+ gtd(check): refactor.closing → refactor.build.quality.correctness.reviewing
169
+ gtd(agent): refactor.build.quality.correctness.reviewing → refactor.build.review.reviewing
170
+ gtd(agent): refactor.build.review.reviewing → refactor.build.review.await-review
171
+ """
172
+
173
+
174
+ Rule: with the refactor lenses blank
175
+
176
+ Background:
177
+ Given an environment variable "GTD_REFACTORQUALITYREVIEWS" set to ""
178
+ And a file "src/calc.ts" with:
179
+ """
180
+ export const add = (a: number, b: number) => a + b
181
+ """
182
+ And a file "src/calc.test.ts" with:
183
+ """
184
+ import { expect, it } from "vitest"
185
+ it("adds", () => expect(1 + 1).toBe(2))
186
+ """
187
+ And a file "src/*.ts" with:
188
+ """
189
+ export const literalGlobName = 1
190
+ """
191
+ And the working tree is committed as "feat: add calculator"
192
+ And a file "TODO.md" with:
193
+ """
194
+ # Add subtract
195
+
196
+ subtract(a, b) returns the difference.
197
+ """
198
+ And step "unwind" changes nothing
199
+ And step "start-gate.check" changes nothing
200
+ And step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
201
+ """
202
+ # Requirements
203
+
204
+ ## Concerns
205
+
206
+ ### Subtract
207
+
208
+ - `subtract(a, b)` returns `a - b`.
209
+ """
210
+ And step "design.gate.answer" changes nothing
211
+ And step "seam.naive" writes "src/calc.ts" with:
212
+ """
213
+ export const add = (a: number, b: number) => a + b
214
+ export const subtract = (a: number, b: number) => a - b
215
+ """
216
+ And judge step "seam.judge" answers:
217
+ """
218
+ [{"id":"shape","answer":"refactor-first","p":0.9}]
219
+ """
220
+ And step "refactor.deriving" runs its script
221
+ And step "refactor.building" writes "src/calc.ts" with:
222
+ """
223
+ export const op = (a: number, b: number, sign: number) => a + sign * b
224
+ export const add = (a: number, b: number) => op(a, b, 1)
225
+ """
226
+ And step "refactor.health.check" changes nothing
227
+ And step "refactor.closing" runs its script
228
+ And step "refactor.build.review.reviewing" writes ".gtd/REVIEW.md" with:
229
+ """
230
+ # Review: abc1234
231
+
232
+ <!-- base: 0000000 -->
233
+
234
+ ## calc
235
+
236
+ - [ ] ./src/calc.ts#1-2
237
+ add built on the shared op
238
+ """
239
+ And step "refactor.build.review.closing" runs its script
240
+
241
+ Scenario: an edit note at the refactor review re-derives the refactor, never the design
242
+ When the process is driven
243
+ Then the process rests at "refactor.build.review.await-review"
244
+ Given a file ".gtd/REVIEW.md" with:
245
+ """
246
+ # Review: abc1234
247
+
248
+ <!-- base: 0000000 -->
249
+
250
+ ## calc
251
+
252
+ - [ ] ./src/calc.ts#1-2
253
+ add built on the shared op[^why]
254
+
255
+ [^why]:
256
+ - H: name the helper `combine`
257
+ """
258
+ And step "refactor.build.review.collecting" writes ".gtd/REFACTOR.md" with:
259
+ """
260
+ Name the shared helper `combine`.
261
+ """
262
+ And step "refactor.build.review.collecting" writes ".gtd/REVIEW.md" with:
263
+ """
264
+ # Review: abc1234
265
+
266
+ <!-- base: 0000000 -->
267
+
268
+ ## calc
269
+
270
+ - [ ] ./src/calc.ts#1-2
271
+ add built on the shared op[^why]
272
+
273
+ [^why]:
274
+ - H: name the helper `combine`
275
+ - A: noted in the refactor package.
276
+ """
277
+ When gtd lands
278
+ And the process is driven
279
+ Then the process rests at "refactor.build.review.await-review"
280
+ And ".gtd/REFACTOR.md" contains "combine"
281
+ Given a file ".gtd/REVIEW.md" with:
282
+ """
283
+ # Review: abc1234
284
+
285
+ <!-- base: 0000000 -->
286
+
287
+ ## calc
288
+
289
+ - [ ] ./src/calc.ts#1-2
290
+ add built on the shared op
291
+ """
292
+ And step "refactor.re-unwind" runs its script
293
+ And step "refactor.building" writes "src/calc.ts" with:
294
+ """
295
+ export const combine = (a: number, b: number, sign: number) => a + sign * b
296
+ export const add = (a: number, b: number) => combine(a, b, 1)
297
+ """
298
+ And step "refactor.deriving" is prompted with "Review feedback"
299
+ When gtd lands
300
+ And the process is driven
301
+ Then the process rests at "refactor.build.review.await-review"
302
+ And the commit subjects end with:
303
+ """
304
+ gtd(human): refactor.build.review.await-review → refactor.build.review.closing
305
+ gtd(check): refactor.build.review.closing → refactor.re-unwind
306
+ gtd(check): refactor.re-unwind → refactor.deriving
307
+ gtd(check): refactor.deriving → refactor.building
308
+ gtd(agent): refactor.building → refactor.health.check
309
+ gtd(check): refactor.health.check → refactor.closing
310
+ gtd(check): refactor.closing → refactor.build.review.reviewing
311
+ gtd(agent): refactor.build.review.reviewing → refactor.build.review.await-review
312
+ """
313
+
314
+ Scenario: the refactor review says the whole refactor on its second round, the feature's feedback review only what is new
315
+ Given step "refactor.build.review.reviewing" is prompted with "it covers the whole refactor since it started, on every round"
316
+ And step "implement.building" writes "src/calc.ts" with:
317
+ """
318
+ export const op = (a: number, b: number, sign: number) => a + sign * b
319
+ export const add = (a: number, b: number) => op(a, b, 1)
320
+ export const subtract = (a: number, b: number) => op(a, b, -1)
321
+ """
322
+ And step "implement.health.check" changes nothing
323
+ And step "implement.closing" runs its script
324
+ And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
325
+ """
326
+ # Review: abc1234
327
+
328
+ <!-- base: 0000000 -->
329
+
330
+ ## calc
331
+
332
+ - [ ] ./src/calc.ts#1-3
333
+ subtract built on the shared op
334
+ """
335
+ When the process is driven
336
+ Then the process rests at "refactor.build.review.await-review"
337
+ Given a file ".gtd/REVIEW.md" with:
338
+ """
339
+ # Review: abc1234
340
+
341
+ <!-- base: 0000000 -->
342
+
343
+ ## calc
344
+
345
+ - [ ] ./src/calc.ts#1-2
346
+ add built on the shared op[^why]
347
+
348
+ [^why]:
349
+ - H: name the helper `combine`
350
+ """
351
+ And step "refactor.build.review.collecting" writes ".gtd/REFACTOR.md" with:
352
+ """
353
+ Name the shared helper `combine`.
354
+ """
355
+ And step "refactor.build.review.collecting" writes ".gtd/REVIEW.md" with:
356
+ """
357
+ # Review: abc1234
358
+
359
+ <!-- base: 0000000 -->
360
+
361
+ ## calc
362
+
363
+ - [ ] ./src/calc.ts#1-2
364
+ add built on the shared op[^why]
365
+
366
+ [^why]:
367
+ - H: name the helper `combine`
368
+ - A: noted in the refactor package.
369
+ """
370
+ When gtd lands
371
+ And the process is driven
372
+ Then the process rests at "refactor.build.review.await-review"
373
+ Given a file ".gtd/REVIEW.md" with:
374
+ """
375
+ # Review: abc1234
376
+
377
+ <!-- base: 0000000 -->
378
+
379
+ ## calc
380
+
381
+ - [ ] ./src/calc.ts#1-2
382
+ add built on the shared op
383
+ """
384
+ And step "refactor.re-unwind" runs its script
385
+ And step "refactor.deriving" runs its script
386
+ And step "refactor.building" writes "src/calc.ts" with:
387
+ """
388
+ export const combine = (a: number, b: number, sign: number) => a + sign * b
389
+ export const add = (a: number, b: number) => combine(a, b, 1)
390
+ """
391
+ When gtd lands
392
+ And the process is driven
393
+ Then the process rests at "refactor.build.review.await-review"
394
+ When gtd lands
395
+ And the process is driven
396
+ Then the process rests at "build.review.await-review"
397
+ Given a file ".gtd/REVIEW.md" with:
398
+ """
399
+ # Review: abc1234
400
+
401
+ <!-- base: 0000000 -->
402
+
403
+ ## calc
404
+
405
+ - [ ] ./src/calc.ts#1-3
406
+ subtract built on the shared op[^m]
407
+
408
+ [^m]:
409
+ - H: also export multiply
410
+ """
411
+ And step "build.review.collecting" writes ".gtd/REQUIREMENTS.md" with:
412
+ """
413
+ # Requirements
414
+
415
+ - multiply
416
+ """
417
+ And step "build.review.collecting" writes ".gtd/REVIEW.md" with:
418
+ """
419
+ # Review: abc1234
420
+
421
+ <!-- base: 0000000 -->
422
+
423
+ ## calc
424
+
425
+ - [ ] ./src/calc.ts#1-3
426
+ subtract built on the shared op[^m]
427
+
428
+ [^m]:
429
+ - H: also export multiply
430
+ - A: noted.
431
+ """
432
+ When gtd lands
433
+ And the process is driven
434
+ Then the process rests at "build.review.await-review"
435
+ Given a file ".gtd/REVIEW.md" with:
436
+ """
437
+ # Review: abc1234
438
+
439
+ <!-- base: 0000000 -->
440
+
441
+ ## calc
442
+
443
+ - [ ] ./src/calc.ts#1-3
444
+ subtract built on the shared op
445
+ """
446
+ And step "build.review.closing" runs its script
447
+ And step "re-unwind" runs its script
448
+ And step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
449
+ """
450
+ # Requirements
451
+
452
+ - multiply, designed
453
+ """
454
+ And step "implement.building" writes "src/calc.ts" with:
455
+ """
456
+ export const op = (a: number, b: number, sign: number) => a + sign * b
457
+ export const add = (a: number, b: number) => op(a, b, 1)
458
+ export const subtract = (a: number, b: number) => op(a, b, -1)
459
+ export const multiply = (a: number, b: number) => a * b
460
+ """
461
+ And step "build.review.reviewing" is prompted with "it covers only what is new since the previous review"
462
+ When gtd lands
463
+ And the process is driven
464
+ Then the process rests at "build.review.await-review"
465
+
466
+ Scenario: a question answered at the refactor review reaches the re-derived package as ### Answered Questions
467
+ When the process is driven
468
+ Then the process rests at "refactor.build.review.await-review"
469
+ Given a file ".gtd/REVIEW.md" with:
470
+ """
471
+ # Review: abc1234
472
+
473
+ <!-- base: 0000000 -->
474
+
475
+ ## calc
476
+
477
+ - [ ] ./src/calc.ts#1-1
478
+ why a shared op?
479
+ - [ ] ./src/calc.ts#2-2
480
+ rename the helper to combine
481
+ """
482
+ And judge step "refactor.build.review.triage" answers:
483
+ """
484
+ [{"id":"note-1","answer":"question","p":0.9},{"id":"note-2","answer":"edit","p":0.9}]
485
+ """
486
+ And step "refactor.build.review.answer-review-questions" writes ".gtd/REVIEW.md" with:
487
+ """
488
+ # Review: abc1234
489
+
490
+ <!-- base: 0000000 -->
491
+
492
+ ## calc
493
+
494
+ - [ ] ./src/calc.ts#1-1
495
+ why a shared op?
496
+ A: add and subtract differ only by sign.
497
+ - [ ] ./src/calc.ts#2-2
498
+ rename the helper to combine
499
+ """
500
+ And step "refactor.build.review.collecting" writes ".gtd/REFACTOR.md" with:
501
+ """
502
+ ## Rename
503
+
504
+ Name the shared helper `combine`.
505
+
506
+ ## Answered Questions
507
+
508
+ ### why a shared op?
509
+
510
+ add and subtract differ only by sign.
511
+ """
512
+ And step "refactor.re-unwind" runs its script
513
+ And step "refactor.deriving" runs its script
514
+ When gtd lands
515
+ And the process is driven
516
+ Then ".gtd/REFACTOR.md" contains "## Review feedback"
517
+ And ".gtd/REFACTOR.md" contains "### Answered Questions"
518
+
519
+ Scenario: a human code edit at the refactor review is reverted by refactor.re-unwind
520
+ When the process is driven
521
+ Then the process rests at "refactor.build.review.await-review"
522
+ Given a file "src/calc.ts" with:
523
+ """
524
+ export const op = (a: number, b: number, sign: number) => a + sign * b
525
+ export const add = (a: number, b: number) => op(a, b, 1)
526
+ // TODO: rename op to adjust
527
+ """
528
+ And step "refactor.build.review.collecting" writes ".gtd/REFACTOR.md" with:
529
+ """
530
+ Rename op to adjust in the shared helper.
531
+ """
532
+ And step "refactor.re-unwind" runs its script
533
+ And step "refactor.building" writes "src/calc.ts" with:
534
+ """
535
+ export const adjust = (a: number, b: number, sign: number) => a + sign * b
536
+ export const add = (a: number, b: number) => adjust(a, b, 1)
537
+ """
538
+ When gtd lands
539
+ And the process is driven
540
+ Then the process rests at "refactor.build.review.await-review"
541
+ And "src/calc.ts" does not contain "TODO"
542
+ And the commit subjects end with:
543
+ """
544
+ gtd(human): refactor.build.review.await-review → refactor.build.review.closing
545
+ gtd(check): refactor.build.review.closing → refactor.build.review.collecting
546
+ gtd(agent): refactor.build.review.collecting → refactor.re-unwind
547
+ gtd(check): refactor.re-unwind → refactor.deriving
548
+ gtd(check): refactor.deriving → refactor.building
549
+ gtd(agent): refactor.building → refactor.health.check
550
+ gtd(check): refactor.health.check → refactor.closing
551
+ gtd(check): refactor.closing → refactor.build.review.reviewing
552
+ gtd(agent): refactor.build.review.reviewing → refactor.build.review.await-review
553
+ """
554
+
555
+ Scenario: an edit note the collecting turn leaves out refuses the landing and never signs off
556
+ When the process is driven
557
+ Then the process rests at "refactor.build.review.await-review"
558
+ Given a file ".gtd/REVIEW.md" with:
559
+ """
560
+ # Review: abc1234
561
+
562
+ <!-- base: 0000000 -->
563
+
564
+ ## calc
565
+
566
+ - [ ] ./src/calc.ts#1-2
567
+ add built on the shared op — this should change behaviour, not just structure
568
+ """
569
+ And judge step "refactor.build.review.triage" answers:
570
+ """
571
+ [{"id":"note-1","answer":"edit","p":0.9}]
572
+ """
573
+ And step "refactor.build.review.collecting" changes nothing
574
+ When gtd lands
575
+ Then driving the process is refused with "refactor-feedback"
576
+ And driving the process is refused with "note-1"
577
+ And driving the process is refused with "gtd abandon"
578
+
579
+ Scenario: a code hand-edit the collecting turn leaves out refuses the landing naming the path
580
+ When the process is driven
581
+ Then the process rests at "refactor.build.review.await-review"
582
+ Given a file "src/calc.ts" with:
583
+ """
584
+ export const op = (a: number, b: number, sign: number) => a + sign * b
585
+ export const add = (a: number, b: number) => op(a, b, 1)
586
+ // TODO: rename op to adjust
587
+ """
588
+ And step "refactor.build.review.collecting" changes nothing
589
+ When gtd lands
590
+ Then driving the process is refused with "refactor-feedback"
591
+ And driving the process is refused with "src/calc.ts"
592
+
593
+ Scenario: a hand-edit round with a line note rests at a closed collecting turn that folds both and holds no reply rules
594
+ When the process is driven
595
+ Then the process rests at "refactor.build.review.await-review"
596
+ Given a file "src/calc.ts" with:
597
+ """
598
+ export const op = (a: number, b: number, sign: number) => a + sign * b
599
+ export const add = (a: number, b: number) => op(a, b, 1)
600
+ // TODO: rename op to adjust
601
+ """
602
+ And a file ".gtd/REVIEW.md" with:
603
+ """
604
+ # Review: abc1234
605
+
606
+ <!-- base: 0000000 -->
607
+
608
+ ## calc
609
+
610
+ - [ ] ./src/calc.ts#1-2 rename the helper
611
+ add built on the shared op
612
+ """
613
+ When gtd lands
614
+ And the process is driven
615
+ Then the process rests at "refactor.build.review.collecting"
616
+ And the resting step's content contains "Fold every hand-edit and every note the human left that round"
617
+ And the resting step's content does not contain "A one-shot footnote needs no reply"
618
+ And the resting step's content does not contain "Code threads waiting on you"
619
+
620
+ Scenario: a praise line note on a hand-edit round is never named by the refusal
621
+ When the process is driven
622
+ Then the process rests at "refactor.build.review.await-review"
623
+ Given a file "src/calc.ts" with:
624
+ """
625
+ export const op = (a: number, b: number, sign: number) => a + sign * b
626
+ export const add = (a: number, b: number) => op(a, b, 1)
627
+ // TODO: rename op to adjust
628
+ """
629
+ And a file ".gtd/REVIEW.md" with:
630
+ """
631
+ # Review: abc1234
632
+
633
+ <!-- base: 0000000 -->
634
+
635
+ ## calc
636
+
637
+ - [ ] ./src/calc.ts#1-2
638
+ add built on the shared op, lovely work
639
+ """
640
+ And step "refactor.build.review.collecting" changes nothing
641
+ When gtd lands
642
+ Then driving the process is refused with "hand-edited src/calc.ts"
643
+ And driving the process is refused without "lovely work"
644
+
645
+ Scenario: a thread question at the refactor review gets one reply and no refactor package
646
+ When the process is driven
647
+ Then the process rests at "refactor.build.review.await-review"
648
+ Given a file ".gtd/REVIEW.md" with:
649
+ """
650
+ # Review: abc1234
651
+
652
+ <!-- base: 0000000 -->
653
+
654
+ ## calc
655
+
656
+ - [ ] ./src/calc.ts#1-2
657
+ add built on the shared op[^q]
658
+
659
+ [^q]:
660
+ - H: why a shared op?
661
+ """
662
+ And step "refactor.build.review.collecting" writes ".gtd/REVIEW.md" with:
663
+ """
664
+ # Review: abc1234
665
+
666
+ <!-- base: 0000000 -->
667
+
668
+ ## calc
669
+
670
+ - [ ] ./src/calc.ts#1-2
671
+ add built on the shared op[^q]
672
+
673
+ [^q]:
674
+ - H: why a shared op?
675
+ - A: add and subtract differ only by sign.
676
+ """
677
+ When gtd lands
678
+ And the process is driven
679
+ Then the process rests at "refactor.build.review.await-review"
680
+ And ".gtd/REFACTOR.md" does not exist
681
+ And ".gtd/REVIEW.md" contains "A: add and subtract differ only by sign."
682
+
683
+ Scenario: a no-change landing after the in-gate reply signs off and the feature slice follows
684
+ Given step "implement.building" writes "src/calc.ts" with:
685
+ """
686
+ export const op = (a: number, b: number, sign: number) => a + sign * b
687
+ export const add = (a: number, b: number) => op(a, b, 1)
688
+ export const subtract = (a: number, b: number) => op(a, b, -1)
689
+ """
690
+ And step "implement.health.check" changes nothing
691
+ And step "implement.closing" runs its script
692
+ And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
693
+ """
694
+ # Review: abc1234
695
+
696
+ <!-- base: 0000000 -->
697
+
698
+ ## calc
699
+
700
+ - [ ] ./src/calc.ts#1-3
701
+ subtract built on the shared op
702
+ """
703
+ When the process is driven
704
+ Then the process rests at "refactor.build.review.await-review"
705
+ Given a file ".gtd/REVIEW.md" with:
706
+ """
707
+ # Review: abc1234
708
+
709
+ <!-- base: 0000000 -->
710
+
711
+ ## calc
712
+
713
+ - [ ] ./src/calc.ts#1-2
714
+ add built on the shared op[^q]
715
+
716
+ [^q]:
717
+ - H: why a shared op?
718
+ """
719
+ And step "refactor.build.review.collecting" writes ".gtd/REVIEW.md" with:
720
+ """
721
+ # Review: abc1234
722
+
723
+ <!-- base: 0000000 -->
724
+
725
+ ## calc
726
+
727
+ - [ ] ./src/calc.ts#1-2
728
+ add built on the shared op[^q]
729
+
730
+ [^q]:
731
+ - H: why a shared op?
732
+ - A: add and subtract differ only by sign.
733
+ """
734
+ When gtd lands
735
+ And the process is driven
736
+ Then the process rests at "refactor.build.review.await-review"
737
+ Given a file ".gtd/REVIEW.md" with:
738
+ """
739
+ # Review: abc1234
740
+
741
+ <!-- base: 0000000 -->
742
+
743
+ ## calc
744
+
745
+ - [ ] ./src/calc.ts#1-2
746
+ add built on the shared op[^q]
747
+
748
+ [^q]:
749
+ - H: why a shared op?
750
+ - A: add and subtract differ only by sign.
751
+ - H: understood, thanks. No change needed.
752
+ """
753
+ And step "refactor.build.review.collecting" writes ".gtd/REVIEW.md" with:
754
+ """
755
+ # Review: abc1234
756
+
757
+ <!-- base: 0000000 -->
758
+
759
+ ## calc
760
+
761
+ - [ ] ./src/calc.ts#1-2
762
+ add built on the shared op
763
+ """
764
+ When gtd lands
765
+ And the process is driven
766
+ Then the process rests at "build.review.await-review"
767
+
768
+ Scenario: a praise-only one-shot footnote signs off and the feature slice follows
769
+ Given step "implement.building" writes "src/calc.ts" with:
770
+ """
771
+ export const op = (a: number, b: number, sign: number) => a + sign * b
772
+ export const add = (a: number, b: number) => op(a, b, 1)
773
+ export const subtract = (a: number, b: number) => op(a, b, -1)
774
+ """
775
+ And step "implement.health.check" changes nothing
776
+ And step "implement.closing" runs its script
777
+ And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
778
+ """
779
+ # Review: abc1234
780
+
781
+ <!-- base: 0000000 -->
782
+
783
+ ## calc
784
+
785
+ - [ ] ./src/calc.ts#1-3
786
+ subtract built on the shared op
787
+ """
788
+ When the process is driven
789
+ Then the process rests at "refactor.build.review.await-review"
790
+ Given a file ".gtd/REVIEW.md" with:
791
+ """
792
+ # Review: abc1234
793
+
794
+ <!-- base: 0000000 -->
795
+
796
+ ## calc
797
+
798
+ - [ ] ./src/calc.ts#1-2
799
+ add built on the shared op[^n1]
800
+
801
+ [^n1]:
802
+ Lovely helper.
803
+ """
804
+ And judge step "refactor.build.review.triage" answers:
805
+ """
806
+ [{"id":"note-1","answer":"praise","p":0.9}]
807
+ """
808
+ When gtd lands
809
+ And the process is driven
810
+ Then the process rests at "build.review.await-review"
811
+
812
+ Scenario: a one-shot footnote judged edit that collecting leaves out refuses naming its anchor
813
+ When the process is driven
814
+ Then the process rests at "refactor.build.review.await-review"
815
+ Given a file ".gtd/REVIEW.md" with:
816
+ """
817
+ # Review: abc1234
818
+
819
+ <!-- base: 0000000 -->
820
+
821
+ ## calc
822
+
823
+ - [ ] ./src/calc.ts#1-2
824
+ add built on the shared op[^n1]
825
+
826
+ [^n1]:
827
+ Rename the helper.
828
+ """
829
+ And judge step "refactor.build.review.triage" answers:
830
+ """
831
+ [{"id":"note-1","answer":"edit","p":0.9}]
832
+ """
833
+ And step "refactor.build.review.collecting" changes nothing
834
+ When gtd lands
835
+ Then driving the process is refused with "refactor-feedback"
836
+ And driving the process is refused with "[^n1]"
837
+ And driving the process is refused with "Rename the helper."
838
+
839
+ Scenario: a one-shot footnote landed after an in-gate thread reply is judged, not signed off unjudged
840
+ When the process is driven
841
+ Then the process rests at "refactor.build.review.await-review"
842
+ Given a file ".gtd/REVIEW.md" with:
843
+ """
844
+ # Review: abc1234
845
+
846
+ <!-- base: 0000000 -->
847
+
848
+ ## calc
849
+
850
+ - [ ] ./src/calc.ts#1-2
851
+ add built on the shared op[^q]
852
+
853
+ [^q]:
854
+ - H: why a shared op?
855
+ """
856
+ And step "refactor.build.review.collecting" writes ".gtd/REVIEW.md" with:
857
+ """
858
+ # Review: abc1234
859
+
860
+ <!-- base: 0000000 -->
861
+
862
+ ## calc
863
+
864
+ - [ ] ./src/calc.ts#1-2
865
+ add built on the shared op[^q]
866
+
867
+ [^q]:
868
+ - H: why a shared op?
869
+ - A: add and subtract differ only by sign.
870
+ """
871
+ When gtd lands
872
+ And the process is driven
873
+ Then the process rests at "refactor.build.review.await-review"
874
+ Given a file ".gtd/REVIEW.md" with:
875
+ """
876
+ # Review: abc1234
877
+
878
+ <!-- base: 0000000 -->
879
+
880
+ ## calc
881
+
882
+ - [ ] ./src/calc.ts#1-2
883
+ add built on the shared op[^n1]
884
+
885
+ [^n1]:
886
+ Rename the helper.
887
+ """
888
+ And judge step "refactor.build.review.triage" answers:
889
+ """
890
+ [{"id":"note-1","answer":"edit","p":0.9}]
891
+ """
892
+ And step "refactor.build.review.collecting" from now on changes nothing
893
+ When gtd lands
894
+ Then driving the process is refused with "refactor-feedback"
895
+ And driving the process is refused with "[^n1]"
896
+
897
+ Scenario: a change note left behind by a thread-only settled round refuses naming the note
898
+ When the process is driven
899
+ Then the process rests at "refactor.build.review.await-review"
900
+ Given a file ".gtd/REVIEW.md" with:
901
+ """
902
+ # Review: abc1234
903
+
904
+ <!-- base: 0000000 -->
905
+
906
+ ## calc
907
+
908
+ - [ ] ./src/calc.ts#1-2
909
+ add built on the shared op - this should change behaviour, not just structure[^q]
910
+
911
+ [^q]:
912
+ - H: why a shared op?
913
+ """
914
+ And step "refactor.build.review.collecting" rewrites ".gtd/REVIEW.md" with:
915
+ """
916
+ # Review: abc1234
917
+
918
+ <!-- base: 0000000 -->
919
+
920
+ ## calc
921
+
922
+ - [ ] ./src/calc.ts#1-2
923
+ add built on the shared op - this should change behaviour, not just structure[^q]
924
+
925
+ [^q]:
926
+ - H: why a shared op?
927
+ - A: add and subtract differ only by sign.
928
+ """
929
+ When gtd lands
930
+ And the process is driven
931
+ Then the process rests at "refactor.build.review.await-review"
932
+ Given a file ".gtd/REVIEW.md" with:
933
+ """
934
+ # Review: abc1234
935
+
936
+ <!-- base: 0000000 -->
937
+
938
+ ## calc
939
+
940
+ - [ ] ./src/calc.ts#1-2
941
+ add built on the shared op - this should change behaviour, not just structure[^q]
942
+
943
+ [^q]:
944
+ - H: why a shared op?
945
+ - A: add and subtract differ only by sign.
946
+ - H: understood, thanks. No change needed.
947
+ """
948
+ And step "refactor.build.review.collecting" rewrites ".gtd/REVIEW.md" with:
949
+ """
950
+ # Review: abc1234
951
+
952
+ <!-- base: 0000000 -->
953
+
954
+ ## calc
955
+
956
+ - [ ] ./src/calc.ts#1-2
957
+ add built on the shared op - this should change behaviour, not just structure
958
+ """
959
+ And judge step "refactor.build.review.triage" answers:
960
+ """
961
+ [{"id":"note-1","answer":"edit","p":0.9}]
962
+ """
963
+ When gtd lands
964
+ Then driving the process is refused with "refactor-feedback"
965
+ And driving the process is refused with "note-1"
966
+ And driving the process is refused with "gtd abandon"
967
+
968
+ Scenario: a hand-edit made before the thread refuses a thread-only settled round naming the path
969
+ When the process is driven
970
+ Then the process rests at "refactor.build.review.await-review"
971
+ Given a file "src/calc.ts" with:
972
+ """
973
+ export const op = (a: number, b: number, sign: number) => a + sign * b
974
+ export const add = (a: number, b: number) => op(a, b, 1)
975
+ // TODO: rename op to adjust
976
+ """
977
+ And a file ".gtd/REVIEW.md" with:
978
+ """
979
+ # Review: abc1234
980
+
981
+ <!-- base: 0000000 -->
982
+
983
+ ## calc
984
+
985
+ - [ ] ./src/calc.ts#1-2
986
+ add built on the shared op[^q]
987
+
988
+ [^q]:
989
+ - H: why a shared op?
990
+ """
991
+ And step "refactor.build.review.collecting" rewrites ".gtd/REVIEW.md" with:
992
+ """
993
+ # Review: abc1234
994
+
995
+ <!-- base: 0000000 -->
996
+
997
+ ## calc
998
+
999
+ - [ ] ./src/calc.ts#1-2
1000
+ add built on the shared op[^q]
1001
+
1002
+ [^q]:
1003
+ - H: why a shared op?
1004
+ - A: add and subtract differ only by sign.
1005
+ """
1006
+ When gtd lands
1007
+ And the process is driven
1008
+ Then the process rests at "refactor.build.review.await-review"
1009
+ Given a file ".gtd/REVIEW.md" with:
1010
+ """
1011
+ # Review: abc1234
1012
+
1013
+ <!-- base: 0000000 -->
1014
+
1015
+ ## calc
1016
+
1017
+ - [ ] ./src/calc.ts#1-2
1018
+ add built on the shared op[^q]
1019
+
1020
+ [^q]:
1021
+ - H: why a shared op?
1022
+ - A: add and subtract differ only by sign.
1023
+ - H: understood, thanks. No change needed.
1024
+ """
1025
+ And step "refactor.build.review.collecting" rewrites ".gtd/REVIEW.md" with:
1026
+ """
1027
+ # Review: abc1234
1028
+
1029
+ <!-- base: 0000000 -->
1030
+
1031
+ ## calc
1032
+
1033
+ - [ ] ./src/calc.ts#1-2
1034
+ add built on the shared op
1035
+ """
1036
+ When gtd lands
1037
+ Then driving the process is refused with "refactor-feedback"
1038
+ And driving the process is refused with "hand-edited src/calc.ts"
1039
+
1040
+ Scenario: a praise note and a concluded thread on a settled round sign off and the feature slice follows
1041
+ Given step "implement.building" writes "src/calc.ts" with:
1042
+ """
1043
+ export const op = (a: number, b: number, sign: number) => a + sign * b
1044
+ export const add = (a: number, b: number) => op(a, b, 1)
1045
+ export const subtract = (a: number, b: number) => op(a, b, -1)
1046
+ """
1047
+ And step "implement.health.check" changes nothing
1048
+ And step "implement.closing" runs its script
1049
+ And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
1050
+ """
1051
+ # Review: abc1234
1052
+
1053
+ <!-- base: 0000000 -->
1054
+
1055
+ ## calc
1056
+
1057
+ - [ ] ./src/calc.ts#1-3
1058
+ subtract built on the shared op
1059
+ """
1060
+ When the process is driven
1061
+ Then the process rests at "refactor.build.review.await-review"
1062
+ Given a file ".gtd/REVIEW.md" with:
1063
+ """
1064
+ # Review: abc1234
1065
+
1066
+ <!-- base: 0000000 -->
1067
+
1068
+ ## calc
1069
+
1070
+ - [ ] ./src/calc.ts#1-2
1071
+ add built on the shared op, lovely work[^q]
1072
+
1073
+ [^q]:
1074
+ - H: why a shared op?
1075
+ """
1076
+ And step "refactor.build.review.collecting" rewrites ".gtd/REVIEW.md" with:
1077
+ """
1078
+ # Review: abc1234
1079
+
1080
+ <!-- base: 0000000 -->
1081
+
1082
+ ## calc
1083
+
1084
+ - [ ] ./src/calc.ts#1-2
1085
+ add built on the shared op, lovely work[^q]
1086
+
1087
+ [^q]:
1088
+ - H: why a shared op?
1089
+ - A: add and subtract differ only by sign.
1090
+ """
1091
+ When gtd lands
1092
+ And the process is driven
1093
+ Then the process rests at "refactor.build.review.await-review"
1094
+ Given a file ".gtd/REVIEW.md" with:
1095
+ """
1096
+ # Review: abc1234
1097
+
1098
+ <!-- base: 0000000 -->
1099
+
1100
+ ## calc
1101
+
1102
+ - [ ] ./src/calc.ts#1-2
1103
+ add built on the shared op, lovely work[^q]
1104
+
1105
+ [^q]:
1106
+ - H: why a shared op?
1107
+ - A: add and subtract differ only by sign.
1108
+ - H: understood, thanks. No change needed.
1109
+ """
1110
+ And step "refactor.build.review.collecting" rewrites ".gtd/REVIEW.md" with:
1111
+ """
1112
+ # Review: abc1234
1113
+
1114
+ <!-- base: 0000000 -->
1115
+
1116
+ ## calc
1117
+
1118
+ - [ ] ./src/calc.ts#1-2
1119
+ add built on the shared op, lovely work
1120
+ """
1121
+ And judge step "refactor.build.review.triage" answers:
1122
+ """
1123
+ [{"id":"note-1","answer":"praise","p":0.9}]
1124
+ """
1125
+ When gtd lands
1126
+ And the process is driven
1127
+ Then the process rests at "build.review.await-review"
1128
+
1129
+ Scenario: a praise-only refactor review still signs off and the feature slice follows
1130
+ Given step "implement.building" writes "src/calc.ts" with:
1131
+ """
1132
+ export const op = (a: number, b: number, sign: number) => a + sign * b
1133
+ export const add = (a: number, b: number) => op(a, b, 1)
1134
+ export const subtract = (a: number, b: number) => op(a, b, -1)
1135
+ """
1136
+ And step "implement.health.check" changes nothing
1137
+ And step "implement.closing" runs its script
1138
+ And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
1139
+ """
1140
+ # Review: abc1234
1141
+
1142
+ <!-- base: 0000000 -->
1143
+
1144
+ ## calc
1145
+
1146
+ - [ ] ./src/calc.ts#1-3
1147
+ subtract built on the shared op
1148
+ """
1149
+ When the process is driven
1150
+ Then the process rests at "refactor.build.review.await-review"
1151
+ Given a file ".gtd/REVIEW.md" with:
1152
+ """
1153
+ # Review: abc1234
1154
+
1155
+ <!-- base: 0000000 -->
1156
+
1157
+ ## calc
1158
+
1159
+ - [x] ./src/calc.ts#1-2
1160
+ add built on the shared op
1161
+ """
1162
+ When gtd lands
1163
+ And the process is driven
1164
+ Then the process rests at "build.review.await-review"
1165
+
1166
+ Scenario: the feature review after a refactor covers only the commits since the refactor's sign-off
1167
+ Given step "implement.building" writes "src/calc.ts" with:
1168
+ """
1169
+ export const op = (a: number, b: number, sign: number) => a + sign * b
1170
+ export const add = (a: number, b: number) => op(a, b, 1)
1171
+ export const subtract = (a: number, b: number) => op(a, b, -1)
1172
+ """
1173
+ And step "implement.health.check" changes nothing
1174
+ And step "implement.closing" runs its script
1175
+ And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
1176
+ """
1177
+ # Review: abc1234
1178
+
1179
+ <!-- base: 0000000 -->
1180
+
1181
+ ## calc
1182
+
1183
+ - [ ] ./src/calc.ts#1-3
1184
+ subtract built on the shared op
1185
+ """
1186
+ When the process is driven
1187
+ Then the process rests at "refactor.build.review.await-review"
1188
+ Given a file ".gtd/REVIEW.md" with:
1189
+ """
1190
+ # Review: abc1234
1191
+
1192
+ <!-- base: 0000000 -->
1193
+
1194
+ ## calc
1195
+
1196
+ - [x] ./src/calc.ts#1-2
1197
+ add built on the shared op
1198
+ """
1199
+ When gtd lands
1200
+ And the process is driven
1201
+ Then the process rests at "build.review.await-review"
1202
+ And the resting step's content contains the hash of the commit "gtd(check): refactor.build.review.closing → implement.building"
1203
+
1204
+ Scenario: feature feedback after a refactor re-plans design and implement, never the seam phase
1205
+ Given step "implement.building" writes "src/calc.ts" with:
1206
+ """
1207
+ export const op = (a: number, b: number, sign: number) => a + sign * b
1208
+ export const add = (a: number, b: number) => op(a, b, 1)
1209
+ export const subtract = (a: number, b: number) => op(a, b, -1)
1210
+ """
1211
+ And step "implement.health.check" changes nothing
1212
+ And step "implement.closing" runs its script
1213
+ And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
1214
+ """
1215
+ # Review: abc1234
1216
+
1217
+ <!-- base: 0000000 -->
1218
+
1219
+ ## calc
1220
+
1221
+ - [ ] ./src/calc.ts#1-3
1222
+ subtract built on the shared op
1223
+ """
1224
+ When the process is driven
1225
+ Then the process rests at "refactor.build.review.await-review"
1226
+ Given a file ".gtd/REVIEW.md" with:
1227
+ """
1228
+ # Review: abc1234
1229
+
1230
+ <!-- base: 0000000 -->
1231
+
1232
+ ## calc
1233
+
1234
+ - [x] ./src/calc.ts#1-2
1235
+ add built on the shared op
1236
+ """
1237
+ When gtd lands
1238
+ And the process is driven
1239
+ Then the process rests at "build.review.await-review"
1240
+ Given a file ".gtd/REVIEW.md" with:
1241
+ """
1242
+ # Review: abc1234
1243
+
1244
+ <!-- base: 0000000 -->
1245
+
1246
+ ## calc
1247
+
1248
+ - [ ] ./src/calc.ts#1-3
1249
+ subtract built on the shared op[^why]
1250
+
1251
+ [^why]:
1252
+ - H: also export multiply
1253
+ """
1254
+ And step "build.review.collecting" writes ".gtd/REQUIREMENTS.md" with:
1255
+ """
1256
+ # Requirements
1257
+
1258
+ ## Concerns
1259
+
1260
+ ### Multiply
1261
+
1262
+ - Export `multiply()`.
1263
+ """
1264
+ And step "build.review.collecting" writes ".gtd/REVIEW.md" with:
1265
+ """
1266
+ # Review: abc1234
1267
+
1268
+ <!-- base: 0000000 -->
1269
+
1270
+ ## calc
1271
+
1272
+ - [ ] ./src/calc.ts#1-3
1273
+ subtract built on the shared op[^why]
1274
+
1275
+ [^why]:
1276
+ - H: also export multiply
1277
+ - A: noted in the requirements.
1278
+ """
1279
+ When gtd lands
1280
+ And the process is driven
1281
+ Then the process rests at "build.review.await-review"
1282
+ Given a file ".gtd/REVIEW.md" with:
1283
+ """
1284
+ # Review: abc1234
1285
+
1286
+ <!-- base: 0000000 -->
1287
+
1288
+ ## calc
1289
+
1290
+ - [ ] ./src/calc.ts#1-3
1291
+ subtract built on the shared op
1292
+ """
1293
+ And step "build.review.closing" runs its script
1294
+ And step "re-unwind" runs its script
1295
+ When gtd lands
1296
+ And the process is driven
1297
+ Then the process rests at "implement.building"
1298
+ And the commit subjects end with:
1299
+ """
1300
+ gtd(check): re-unwind → design.triage
1301
+ gtd(agent): design.triage → design.gate.answer
1302
+ gtd(human): design.gate.answer → implement.building
1303
+ gtd(agent): implement.building
1304
+ """
1305
+
1306
+ Scenario: a nit fix in the refactor slice that changes a non-stray is refused, though a glob stray widens the write access
1307
+ Given step "seam.naive" writes "src/*.ts" with:
1308
+ """
1309
+ export const literalGlobName = 2
1310
+ """
1311
+ When the process is driven
1312
+ Then the process rests at "refactor.build.review.await-review"
1313
+ Given a file ".gtd/REVIEW.md" with:
1314
+ """
1315
+ # Review: abc1234
1316
+
1317
+ <!-- base: 0000000 -->
1318
+
1319
+ ## calc
1320
+
1321
+ - [ ] ./src/calc.ts#1-2
1322
+ add built on the shared op — rename `sign` to `direction`
1323
+ """
1324
+ And judge step "refactor.build.review.triage" answers:
1325
+ """
1326
+ [{"id":"note-1","answer":"nit","p":0.9}]
1327
+ """
1328
+ And step "refactor.build.review.fix.nits.fixing" writes "src/other.ts" with:
1329
+ """
1330
+ export const other = 1
1331
+ """
1332
+ When gtd lands
1333
+ Then driving the process is refused with "refactor-scope"
1334
+
1335
+ Scenario: the nit-fix turn in the refactor slice may write the strays and .gtd/** only
1336
+ Given step "seam.naive" writes "src/*.ts" with:
1337
+ """
1338
+ export const literalGlobName = 2
1339
+ """
1340
+ When the process is driven
1341
+ Then the process rests at "refactor.build.review.await-review"
1342
+ Given a file ".gtd/REVIEW.md" with:
1343
+ """
1344
+ # Review: abc1234
1345
+
1346
+ <!-- base: 0000000 -->
1347
+
1348
+ ## calc
1349
+
1350
+ - [ ] ./src/calc.ts#1-2
1351
+ add built on the shared op — rename `sign` to `direction`
1352
+ """
1353
+ And judge step "refactor.build.review.triage" answers:
1354
+ """
1355
+ [{"id":"note-1","answer":"nit","p":0.9}]
1356
+ """
1357
+ When gtd lands
1358
+ And the process is driven
1359
+ Then the process rests at "refactor.build.review.fix.nits.fixing"
1360
+ And the output of gtd "next --json=access.write" contains "src/*.ts"
1361
+ And the output of gtd "next --json=access.write" contains ".gtd/**"
1362
+
1363
+ Scenario: a blank refactorQualityReviews runs no refactor quality lap
1364
+ When the process is driven
1365
+ Then the process rests at "refactor.build.review.await-review"
1366
+ And the commit subjects end with:
1367
+ """
1368
+ gtd(check): refactor.closing → refactor.build.review.reviewing
1369
+ gtd(agent): refactor.build.review.reviewing → refactor.build.review.await-review
1370
+ """
1371
+
1372
+ Rule: with a quality lens on both slices
1373
+
1374
+ Background:
1375
+ Given an environment variable "GTD_REFACTORQUALITYREVIEWS" set to "correctness"
1376
+ And an environment variable "GTD_QUALITYREVIEWS" set to "correctness"
1377
+ And a file "src/calc.ts" with:
1378
+ """
1379
+ export const add = (a: number, b: number) => a + b
1380
+ """
1381
+ And a file "src/calc.test.ts" with:
1382
+ """
1383
+ import { expect, it } from "vitest"
1384
+ it("adds", () => expect(1 + 1).toBe(2))
1385
+ """
1386
+ And a file "src/*.ts" with:
1387
+ """
1388
+ export const literalGlobName = 1
1389
+ """
1390
+ And the working tree is committed as "feat: add calculator"
1391
+ And a file "TODO.md" with:
1392
+ """
1393
+ # Add subtract
1394
+
1395
+ subtract(a, b) returns the difference.
1396
+ """
1397
+ And step "unwind" changes nothing
1398
+ And step "start-gate.check" changes nothing
1399
+ And step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
1400
+ """
1401
+ # Requirements
1402
+
1403
+ ## Concerns
1404
+
1405
+ ### Subtract
1406
+
1407
+ - `subtract(a, b)` returns `a - b`.
1408
+ """
1409
+ And step "design.gate.answer" changes nothing
1410
+ And step "seam.naive" writes "src/calc.ts" with:
1411
+ """
1412
+ export const add = (a: number, b: number) => a + b
1413
+ export const subtract = (a: number, b: number) => a - b
1414
+ """
1415
+ And judge step "seam.judge" answers:
1416
+ """
1417
+ [{"id":"shape","answer":"refactor-first","p":0.9}]
1418
+ """
1419
+ And step "refactor.deriving" runs its script
1420
+ And step "refactor.building" writes "src/calc.ts" with:
1421
+ """
1422
+ export const op = (a: number, b: number, sign: number) => a + sign * b
1423
+ export const add = (a: number, b: number) => op(a, b, 1)
1424
+ """
1425
+ And step "refactor.health.check" changes nothing
1426
+ And step "refactor.closing" runs its script
1427
+ And step "refactor.build.review.reviewing" writes ".gtd/REVIEW.md" with:
1428
+ """
1429
+ # Review: abc1234
1430
+
1431
+ <!-- base: 0000000 -->
1432
+
1433
+ ## calc
1434
+
1435
+ - [ ] ./src/calc.ts#1-2
1436
+ add built on the shared op
1437
+ """
1438
+ And step "refactor.build.review.closing" runs its script
1439
+
1440
+ Scenario: each slice's quality lap reviews from that slice's base, before and after a feature feedback lap
1441
+ When the process is driven
1442
+ Then the process rests at "refactor.build.quality.correctness.reviewing"
1443
+ And the resting step's content contains the hash of the commit "gtd(judge): seam.judge → refactor.deriving"
1444
+ Given step "refactor.build.quality.correctness.reviewing" changes nothing
1445
+ And step "implement.building" writes "src/calc.ts" with:
1446
+ """
1447
+ export const op = (a: number, b: number, sign: number) => a + sign * b
1448
+ export const add = (a: number, b: number) => op(a, b, 1)
1449
+ export const subtract = (a: number, b: number) => op(a, b, -1)
1450
+ """
1451
+ And step "implement.health.check" changes nothing
1452
+ And step "implement.closing" runs its script
1453
+ When the process is driven
1454
+ Then the process rests at "refactor.build.review.await-review"
1455
+ Given a file ".gtd/REVIEW.md" with:
1456
+ """
1457
+ # Review: abc1234
1458
+
1459
+ <!-- base: 0000000 -->
1460
+
1461
+ ## calc
1462
+
1463
+ - [x] ./src/calc.ts#1-2
1464
+ add built on the shared op
1465
+ """
1466
+ When gtd lands
1467
+ And the process is driven
1468
+ Then the process rests at "build.quality.correctness.reviewing"
1469
+ And the resting step's content contains the hash of the commit "gtd(check): refactor.build.review.closing → implement.building"
1470
+ Given step "build.quality.correctness.reviewing" changes nothing
1471
+ And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
1472
+ """
1473
+ # Review: abc1234
1474
+
1475
+ <!-- base: 0000000 -->
1476
+
1477
+ ## calc
1478
+
1479
+ - [ ] ./src/calc.ts#1-3
1480
+ subtract built on the shared op
1481
+ """
1482
+ When the process is driven
1483
+ Then the process rests at "build.review.await-review"
1484
+ Given a file ".gtd/REVIEW.md" with:
1485
+ """
1486
+ # Review: abc1234
1487
+
1488
+ <!-- base: 0000000 -->
1489
+
1490
+ ## calc
1491
+
1492
+ - [ ] ./src/calc.ts#1-3
1493
+ subtract built on the shared op[^why]
1494
+
1495
+ [^why]:
1496
+ - H: also export multiply
1497
+ """
1498
+ And step "build.review.collecting" writes ".gtd/REQUIREMENTS.md" with:
1499
+ """
1500
+ # Requirements
1501
+
1502
+ ## Concerns
1503
+
1504
+ ### Multiply
1505
+
1506
+ - Export `multiply()`.
1507
+ """
1508
+ And step "build.review.collecting" writes ".gtd/REVIEW.md" with:
1509
+ """
1510
+ # Review: abc1234
1511
+
1512
+ <!-- base: 0000000 -->
1513
+
1514
+ ## calc
1515
+
1516
+ - [ ] ./src/calc.ts#1-3
1517
+ subtract built on the shared op[^why]
1518
+
1519
+ [^why]:
1520
+ - H: also export multiply
1521
+ - A: noted in the requirements.
1522
+ """
1523
+ When gtd lands
1524
+ And the process is driven
1525
+ Then the process rests at "build.review.await-review"
1526
+ Given a file ".gtd/REVIEW.md" with:
1527
+ """
1528
+ # Review: abc1234
1529
+
1530
+ <!-- base: 0000000 -->
1531
+
1532
+ ## calc
1533
+
1534
+ - [ ] ./src/calc.ts#1-3
1535
+ subtract built on the shared op
1536
+ """
1537
+ And step "build.review.closing" runs its script
1538
+ And step "re-unwind" runs its script
1539
+ And step "build.quality.correctness.reviewing" is no longer scripted
1540
+ And step "implement.building" writes "src/calc.ts" with:
1541
+ """
1542
+ export const op = (a: number, b: number, sign: number) => a + sign * b
1543
+ export const add = (a: number, b: number) => op(a, b, 1)
1544
+ export const subtract = (a: number, b: number) => op(a, b, -1)
1545
+ export const multiply = (a: number, b: number) => a * b
1546
+ """
1547
+ And step "implement.health.check" changes nothing
1548
+ And step "implement.closing" runs its script
1549
+ When gtd lands
1550
+ And the process is driven
1551
+ Then the process rests at "build.quality.correctness.reviewing"
1552
+ And the resting step's content contains the hash of the commit "gtd(check): refactor.build.review.closing → implement.building"
1553
+
1554
+ Rule: a refactor package never carries a test file, and demoted headings stop at ######
1555
+
1556
+ Background:
1557
+ Given an environment variable "GTD_REFACTORQUALITYREVIEWS" set to ""
1558
+ And an environment variable "GTD_SEAMALLOW" set to "docs/**"
1559
+ And a file "src/calc.ts" with:
1560
+ """
1561
+ export const add = (a: number, b: number) => a + b
1562
+ """
1563
+ And a file "src/calc.test.ts" with:
1564
+ """
1565
+ import { expect, it } from "vitest"
1566
+ it("adds", () => expect(1 + 1).toBe(2))
1567
+ """
1568
+ And the working tree is committed as "feat: add calculator"
1569
+ And a file "TODO.md" with:
1570
+ """
1571
+ # Add subtract
1572
+
1573
+ subtract(a, b) returns the difference.
1574
+ """
1575
+ And step "unwind" changes nothing
1576
+ And step "start-gate.check" changes nothing
1577
+ And step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
1578
+ """
1579
+ # Requirements
1580
+
1581
+ ## Concerns
1582
+
1583
+ ### Subtract
1584
+
1585
+ - `subtract(a, b)` returns `a - b`.
1586
+ """
1587
+ And step "design.gate.answer" changes nothing
1588
+ And judge step "seam.judge" answers:
1589
+ """
1590
+ [{"id":"shape","answer":"refactor-first","p":0.9}]
1591
+ """
1592
+
1593
+ Scenario: a test-file stray is dropped from the derived refactor package
1594
+ Given step "seam.naive" writes "src/calc.ts" with:
1595
+ """
1596
+ export const add = (a: number, b: number) => a + b
1597
+ export const subtract = (a: number, b: number) => a - b
1598
+ """
1599
+ And step "seam.naive" writes "src/calc.test.ts" with:
1600
+ """
1601
+ import { expect, it } from "vitest"
1602
+ it("subtracts", () => expect(3 - 1).toBe(2))
1603
+ """
1604
+ And step "refactor.deriving" runs its script
1605
+ When the process is driven
1606
+ Then the process rests at "refactor.building"
1607
+ And ".gtd/REFACTOR.md" contains "src/calc.ts"
1608
+ And ".gtd/REFACTOR.md" does not contain "src/calc.test.ts"
1609
+
1610
+ Scenario: a refactor-first whose strays are all test files goes straight to implement
1611
+ Given step "seam.naive" writes "src/calc.test.ts" with:
1612
+ """
1613
+ import { expect, it } from "vitest"
1614
+ it("subtracts", () => expect(3 - 1).toBe(2))
1615
+ """
1616
+ When the process is driven
1617
+ Then the process rests at "implement.building"
1618
+ And ".gtd/REFACTOR.md" does not exist
1619
+
1620
+ Scenario: collected review headings re-derive at ### with the deepest capped at ######
1621
+ Given step "seam.naive" writes "src/calc.ts" with:
1622
+ """
1623
+ export const add = (a: number, b: number) => a + b
1624
+ export const subtract = (a: number, b: number) => a - b
1625
+ """
1626
+ And step "refactor.deriving" runs its script
1627
+ And step "refactor.building" writes "src/calc.ts" with:
1628
+ """
1629
+ export const op = (a: number, b: number, sign: number) => a + sign * b
1630
+ export const add = (a: number, b: number) => op(a, b, 1)
1631
+ """
1632
+ And step "refactor.health.check" changes nothing
1633
+ And step "refactor.closing" runs its script
1634
+ And step "refactor.build.review.reviewing" writes ".gtd/REVIEW.md" with:
1635
+ """
1636
+ # Review: abc1234
1637
+
1638
+ <!-- base: 0000000 -->
1639
+
1640
+ ## calc
1641
+
1642
+ - [ ] ./src/calc.ts#1-2
1643
+ add built on the shared op
1644
+ """
1645
+ When the process is driven
1646
+ Then the process rests at "refactor.build.review.await-review"
1647
+ Given a file ".gtd/REVIEW.md" with:
1648
+ """
1649
+ # Review: abc1234
1650
+
1651
+ <!-- base: 0000000 -->
1652
+
1653
+ ## calc
1654
+
1655
+ - [ ] ./src/calc.ts#1-2
1656
+ add built on the shared op[^why]
1657
+
1658
+ [^why]:
1659
+ - H: name the helper `combine`
1660
+ """
1661
+ And step "refactor.build.review.collecting" writes ".gtd/REFACTOR.md" with:
1662
+ """
1663
+ # Rename
1664
+
1665
+ ##### Detail
1666
+
1667
+ Name the shared helper `combine`.
1668
+ """
1669
+ And step "refactor.build.review.collecting" writes ".gtd/REVIEW.md" with:
1670
+ """
1671
+ # Review: abc1234
1672
+
1673
+ <!-- base: 0000000 -->
1674
+
1675
+ ## calc
1676
+
1677
+ - [ ] ./src/calc.ts#1-2
1678
+ add built on the shared op[^why]
1679
+
1680
+ [^why]:
1681
+ - H: name the helper `combine`
1682
+ - A: noted in the refactor package.
1683
+ """
1684
+ When gtd lands
1685
+ And the process is driven
1686
+ Then the process rests at "refactor.build.review.await-review"
1687
+ Given a file ".gtd/REVIEW.md" with:
1688
+ """
1689
+ # Review: abc1234
1690
+
1691
+ <!-- base: 0000000 -->
1692
+
1693
+ ## calc
1694
+
1695
+ - [ ] ./src/calc.ts#1-2
1696
+ add built on the shared op
1697
+ """
1698
+ And step "refactor.build.review.closing" runs its script
1699
+ And step "refactor.re-unwind" runs its script
1700
+ And step "refactor.building" is no longer scripted
1701
+ When gtd lands
1702
+ And the process is driven
1703
+ Then the process rests at "refactor.building"
1704
+ And ".gtd/REFACTOR.md" contains "## Review feedback"
1705
+ And ".gtd/REFACTOR.md" contains "### Rename"
1706
+ And ".gtd/REFACTOR.md" contains "###### Detail"