@pmelab/gtd 41.0.0 → 43.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 (73) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +107 -53
  3. package/claude/hooks/sketch.ts +1 -1
  4. package/dist/chunks/{reserved-Ch4LLrEj.mjs → reserved-COEMFEpy.mjs} +84 -51
  5. package/dist/chunks/{steering-DVILanVf.mjs → steering-D4LUQ-av.mjs} +95 -12
  6. package/dist/chunks/tail-C_xn8U7U.mjs +246 -0
  7. package/dist/flows.mjs +11 -1
  8. package/dist/gtd.bundle.mjs +498 -30
  9. package/dist/steering.mjs +2 -2
  10. package/dist/testkit.mjs +460 -28
  11. package/dist/web/main.js +42 -13
  12. package/dist/workflow-kit.mjs +61 -25
  13. package/dist/workflows/cleanup.mjs +2 -2
  14. package/dist/workflows/feature.mjs +66 -57
  15. package/dist/workflows/fix.mjs +3 -3
  16. package/dist/workflows/review.mjs +2 -2
  17. package/dist/workflows/rollout.mjs +1 -1
  18. package/dist/workflows.mjs +446 -141
  19. package/package.json +1 -1
  20. package/src/cli/Cli.test.ts +33 -1
  21. package/src/cli/Cli.ts +70 -6
  22. package/src/cli/History.ts +15 -0
  23. package/src/cli/Judges.test.ts +373 -0
  24. package/src/cli/Judges.ts +624 -0
  25. package/src/cli/Metrics.ts +3 -16
  26. package/src/cli/Program.test.ts +3 -1
  27. package/src/cli/Program.ts +9 -0
  28. package/src/flows/scripts.ts +15 -0
  29. package/src/steering/index.ts +12 -1
  30. package/src/steering/review.test.ts +109 -20
  31. package/src/steering/review.ts +160 -9
  32. package/src/testkit/EmittedScriptRecognizer.ts +0 -14
  33. package/src/testkit/FlowScripts.test.ts +17 -0
  34. package/src/testkit/FlowScripts.ts +15 -0
  35. package/src/testkit/steps.ts +31 -0
  36. package/src/workflow-kit/review.test.ts +170 -26
  37. package/src/workflow-kit/review.ts +95 -19
  38. package/src/workflows/feature/coverage.feature +3 -3
  39. package/src/workflows/feature/fast-path.feature +2 -2
  40. package/src/workflows/feature/feature.test.ts +2 -37
  41. package/src/workflows/feature/feature.ts +12 -14
  42. package/src/workflows/feature/flag-mode.feature +2 -2
  43. package/src/workflows/feature/lens-review.feature +246 -0
  44. package/src/workflows/feature/one-step-land.feature +2 -2
  45. package/src/workflows/feature/quality-unresolved.feature +47 -32
  46. package/src/workflows/feature/refactor-absorbs.feature +3 -3
  47. package/src/workflows/feature/refactor-first.feature +5 -5
  48. package/src/workflows/feature/refactor-rebuild.feature +7 -7
  49. package/src/workflows/feature/refactor-review.feature +19 -100
  50. package/src/workflows/feature/refactor.test.ts +12 -27
  51. package/src/workflows/feature/refactor.ts +0 -1
  52. package/src/workflows/feature/review-answers.feature +179 -0
  53. package/src/workflows/feature/review-gate.feature +6 -6
  54. package/src/workflows/feature/review.test.ts +33 -77
  55. package/src/workflows/feature/review.ts +79 -47
  56. package/src/workflows/feature/seam-rejection.feature +2 -2
  57. package/src/workflows/feature/seam.feature +2 -2
  58. package/src/workflows/feature/seam.test.ts +1 -1
  59. package/src/workflows/feature/slicing.feature +6 -6
  60. package/src/workflows/feature/steps.test.ts +0 -12
  61. package/src/workflows/feature/steps.ts +3 -10
  62. package/src/workflows/index.ts +1 -0
  63. package/src/workflows/shared/__fixtures__/feature-collecting-prompt.txt +6 -5
  64. package/src/workflows/shared/access.test.ts +2 -11
  65. package/src/workflows/shared/access.ts +0 -2
  66. package/src/workflows/shared/lenses.test.ts +39 -0
  67. package/src/workflows/shared/lenses.ts +176 -0
  68. package/src/workflows/shared/options.ts +1 -0
  69. package/src/workflows/shared/tail.ts +19 -4
  70. package/src/workflows/shared/text.test.ts +106 -88
  71. package/src/workflows/shared/text.ts +164 -53
  72. package/src/workflows/shared/vars.ts +1 -0
  73. package/dist/chunks/tail-lY1UmJrU.mjs +0 -112
@@ -78,7 +78,7 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
78
78
  """
79
79
  And step "refactor.health.check" changes nothing
80
80
  And step "refactor.closing" runs its script
81
- And step "refactor.build.review.reviewing" writes ".gtd/REVIEW.md" with:
81
+ And step "refactor.build.review.composing" writes ".gtd/REVIEW.md" with:
82
82
  """
83
83
  # Review: abc1234
84
84
 
@@ -171,7 +171,7 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
171
171
  """
172
172
  And step "refactor.health.check" changes nothing
173
173
  And step "refactor.closing" runs its script
174
- And step "refactor.build.review.reviewing" writes ".gtd/REVIEW.md" with:
174
+ And step "refactor.build.review.composing" writes ".gtd/REVIEW.md" with:
175
175
  """
176
176
  # Review: abc1234
177
177
 
@@ -191,8 +191,8 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
191
191
  And the commit subjects end with:
192
192
  """
193
193
  gtd(check): refactor.closing → refactor.build.quality.correctness.reviewing
194
- gtd(agent): refactor.build.quality.correctness.reviewing → refactor.build.review.reviewing
195
- gtd(agent): refactor.build.review.reviewing → refactor.build.review.await-review
194
+ gtd(agent): refactor.build.quality.correctness.reviewing → refactor.build.review.composing
195
+ gtd(check): refactor.build.review.composing → refactor.build.review.await-review
196
196
  """
197
197
 
198
198
 
@@ -263,7 +263,7 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
263
263
  """
264
264
  And step "refactor.health.check" changes nothing
265
265
  And step "refactor.closing" runs its script
266
- And step "refactor.build.review.reviewing" writes ".gtd/REVIEW.md" with:
266
+ And step "refactor.build.review.composing" writes ".gtd/REVIEW.md" with:
267
267
  """
268
268
  # Review: abc1234
269
269
 
@@ -345,91 +345,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
345
345
  gtd(check): refactor.deriving → refactor.building
346
346
  gtd(agent): refactor.building → refactor.health.check
347
347
  gtd(check): refactor.health.check → refactor.closing
348
- gtd(check): refactor.closing → refactor.build.review.reviewing
349
- gtd(agent): refactor.build.review.reviewing → refactor.build.review.await-review
348
+ gtd(check): refactor.closing → refactor.build.review.composing
349
+ gtd(check): refactor.build.review.composing → refactor.build.review.await-review
350
350
  """
351
351
 
352
- Scenario: the refactor review says the whole refactor on its second round
353
- Given step "refactor.build.review.reviewing" is prompted with "it covers the whole refactor since it started, on every round"
354
- And step "implement.building" writes "src/calc.ts" with:
355
- """
356
- export const op = (a: number, b: number, sign: number) => a + sign * b
357
- export const add = (a: number, b: number) => op(a, b, 1)
358
- export const subtract = (a: number, b: number) => op(a, b, -1)
359
- """
360
- And step "implement.building" writes "src/acceptance.test.ts" with:
361
- """
362
- it("[AC-1] holds", () => {})
363
- """
364
- And step "implement.health.check" changes nothing
365
- And step "implement.closing" runs its script
366
- And judge step "implement.coverage" answers:
367
- """
368
- [{"id":"AC-1","answer":"yes","p":0.9}]
369
- """
370
- When the process is driven
371
- Then the process rests at "refactor.build.review.await-review"
372
- Given a file ".gtd/REVIEW.md" with:
373
- """
374
- # Review: abc1234
375
-
376
- <!-- base: 0000000 -->
377
-
378
- ## calc
379
-
380
- - [ ] ./src/calc.ts#1-2
381
- add built on the shared op[^why]
382
-
383
- [^why]:
384
- - H: name the helper `combine`
385
- """
386
- And step "refactor.build.review.collecting" writes ".gtd/REFACTOR.md" with:
387
- """
388
- Name the shared helper `combine`.
389
- """
390
- And step "refactor.build.review.collecting" writes ".gtd/REVIEW.md" with:
391
- """
392
- # Review: abc1234
393
-
394
- <!-- base: 0000000 -->
395
-
396
- ## calc
397
-
398
- - [ ] ./src/calc.ts#1-2
399
- add built on the shared op[^why]
400
-
401
- [^why]:
402
- - H: name the helper `combine`
403
- - A: noted in the refactor package.
404
- """
405
- When gtd lands
406
- And the process is driven
407
- Then the process rests at "refactor.build.review.await-review"
408
- Given a file ".gtd/REVIEW.md" with:
409
- """
410
- # Review: abc1234
411
-
412
- <!-- base: 0000000 -->
413
-
414
- ## calc
415
-
416
- - [ ] ./src/calc.ts#1-2
417
- add built on the shared op
418
- """
419
- And step "refactor.re-unwind" runs its script
420
- And step "refactor.deriving" runs its script
421
- And step "refactor.building" writes "src/calc.ts" with:
422
- """
423
- export const combine = (a: number, b: number, sign: number) => a + sign * b
424
- export const add = (a: number, b: number) => combine(a, b, 1)
425
- """
426
- When gtd lands
427
- And the process is driven
428
- Then the process rests at "refactor.build.review.await-review"
429
- When gtd lands
430
- And the process is driven
431
- Then the process rests at "build.review.reviewing"
432
-
433
352
  Scenario: a question answered at the refactor review reaches the re-derived package as ### Answered Questions
434
353
  When the process is driven
435
354
  Then the process rests at "refactor.build.review.await-review"
@@ -515,8 +434,8 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
515
434
  gtd(check): refactor.deriving → refactor.building
516
435
  gtd(agent): refactor.building → refactor.health.check
517
436
  gtd(check): refactor.health.check → refactor.closing
518
- gtd(check): refactor.closing → refactor.build.review.reviewing
519
- gtd(agent): refactor.build.review.reviewing → refactor.build.review.await-review
437
+ gtd(check): refactor.closing → refactor.build.review.composing
438
+ gtd(check): refactor.build.review.composing → refactor.build.review.await-review
520
439
  """
521
440
 
522
441
  Scenario: an edit note the collecting turn leaves out refuses the landing and never signs off
@@ -727,7 +646,7 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
727
646
  """
728
647
  When gtd lands
729
648
  And the process is driven
730
- Then the process rests at "build.review.reviewing"
649
+ Then the process rests at "build.review.composing"
731
650
  And "src/calc.ts" contains "subtract"
732
651
 
733
652
  Scenario: a praise-only one-shot footnote signs off and the feature slice follows
@@ -769,7 +688,7 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
769
688
  """
770
689
  When gtd lands
771
690
  And the process is driven
772
- Then the process rests at "build.review.reviewing"
691
+ Then the process rests at "build.review.composing"
773
692
  And "src/calc.ts" contains "subtract"
774
693
 
775
694
  Scenario: a one-shot footnote judged edit that collecting leaves out refuses naming its anchor
@@ -1084,7 +1003,7 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
1084
1003
  """
1085
1004
  When gtd lands
1086
1005
  And the process is driven
1087
- Then the process rests at "build.review.reviewing"
1006
+ Then the process rests at "build.review.composing"
1088
1007
  And "src/calc.ts" contains "subtract"
1089
1008
 
1090
1009
  Scenario: a praise-only refactor review still signs off and the feature slice follows
@@ -1119,7 +1038,7 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
1119
1038
  """
1120
1039
  When gtd lands
1121
1040
  And the process is driven
1122
- Then the process rests at "build.review.reviewing"
1041
+ Then the process rests at "build.review.composing"
1123
1042
  And "src/calc.ts" contains "subtract"
1124
1043
 
1125
1044
  Scenario: a nit fix in the refactor slice that changes a non-stray is refused, though a glob stray widens the write access
@@ -1184,8 +1103,8 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
1184
1103
  Then the process rests at "refactor.build.review.await-review"
1185
1104
  And the commit subjects end with:
1186
1105
  """
1187
- gtd(check): refactor.closing → refactor.build.review.reviewing
1188
- gtd(agent): refactor.build.review.reviewing → refactor.build.review.await-review
1106
+ gtd(check): refactor.closing → refactor.build.review.composing
1107
+ gtd(check): refactor.build.review.composing → refactor.build.review.await-review
1189
1108
  """
1190
1109
 
1191
1110
  Rule: with a quality lens on both slices
@@ -1256,7 +1175,7 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
1256
1175
  """
1257
1176
  And step "refactor.health.check" changes nothing
1258
1177
  And step "refactor.closing" runs its script
1259
- And step "refactor.build.review.reviewing" writes ".gtd/REVIEW.md" with:
1178
+ And step "refactor.build.review.composing" writes ".gtd/REVIEW.md" with:
1260
1179
  """
1261
1180
  # Review: abc1234
1262
1181
 
@@ -1309,11 +1228,11 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
1309
1228
  And the resting step's content contains the hash of the commit "gtd(check): refactor.build.review.closing → implement.building"
1310
1229
  Given step "build.quality.correctness.reviewing" changes nothing
1311
1230
  When the process is driven
1312
- Then the process rests at "build.review.reviewing"
1231
+ Then the process rests at "build.review.composing"
1313
1232
  And the commit subjects end with:
1314
1233
  """
1315
1234
  gtd(check): implement.closing → build.quality.correctness.reviewing
1316
- gtd(agent): build.quality.correctness.reviewing → build.review.reviewing
1235
+ gtd(agent): build.quality.correctness.reviewing → build.review.composing
1317
1236
  """
1318
1237
 
1319
1238
  Rule: a refactor package never carries a test file, and demoted headings stop at ######
@@ -1463,7 +1382,7 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
1463
1382
  """
1464
1383
  And step "refactor.health.check" changes nothing
1465
1384
  And step "refactor.closing" runs its script
1466
- And step "refactor.build.review.reviewing" writes ".gtd/REVIEW.md" with:
1385
+ And step "refactor.build.review.composing" writes ".gtd/REVIEW.md" with:
1467
1386
  """
1468
1387
  # Review: abc1234
1469
1388
 
@@ -781,8 +781,6 @@ interface ReviewedScript {
781
781
  /** The collecting turn writes no package. */
782
782
  readonly silentCollect?: boolean
783
783
  readonly collected?: string
784
- /** The note the first `review.reviewing` turn writes; later ones write `add`. */
785
- readonly firstReviewNote?: string
786
784
  }
787
785
 
788
786
  /** Runs `reviewedRefactor` against a scripted context; a third await-review stops the run. */
@@ -797,7 +795,6 @@ const driveReviewed = async (
797
795
  const files = new Map<string, string>()
798
796
  let last = ""
799
797
  let awaits = 0
800
- let reviews = 0
801
798
  let reds = script.reds ?? 0
802
799
  let checking = false
803
800
  let pending: boolean | Error = false
@@ -823,9 +820,7 @@ const driveReviewed = async (
823
820
  ...Object.fromEntries(lensEffects),
824
821
  deriving: () => void files.set(REFACTOR_PACKAGE, "package"),
825
822
  closing: () => void files.delete(REFACTOR_PACKAGE),
826
- "review.reviewing": () => {
827
- files.set(REVIEW, reviewDoc(reviews++ === 0 ? (script.firstReviewNote ?? "add") : "add"))
828
- },
823
+ "review.composing": () => void files.set(REVIEW, reviewDoc("add")),
829
824
  "review.closing": () => void files.delete(REVIEW),
830
825
  "review.collecting": () => {
831
826
  if (!script.silentCollect)
@@ -846,6 +841,14 @@ const driveReviewed = async (
846
841
  if (request.kind === "restart") return Promise.resolve()
847
842
  record(request)
848
843
  effects[request.name]?.()
844
+ // Every lens finding is mechanical, so the fix turn runs.
845
+ if (request.kind === "judge" && request.name === "quality.triage")
846
+ return Promise.resolve({
847
+ answers: Object.fromEntries(
848
+ request.questions.map((q) => [q.id, { answer: "mechanical", p: 0.9 }]),
849
+ ),
850
+ truncated: [],
851
+ })
849
852
  return Promise.resolve(
850
853
  request.kind === "judge" ? { answers: script.answers ?? {}, truncated: [] } : undefined,
851
854
  )
@@ -926,7 +929,7 @@ describe("reviewedRefactor", () => {
926
929
  "refactor.build.quality.correctness.reviewing",
927
930
  "refactor.build.quality.ponytail-review.reviewing",
928
931
  "refactor.build.quality.conventions.reviewing",
929
- "refactor.build.review.reviewing",
932
+ "refactor.build.review.composing",
930
933
  "refactor.build.review.await-review",
931
934
  "refactor.build.review.closing",
932
935
  ])
@@ -934,8 +937,8 @@ describe("reviewedRefactor", () => {
934
937
 
935
938
  it("reviews from HEAD at scope entry", async () => {
936
939
  const h = await driveReviewed(shape())
937
- const reviewing = h.steps.find((s) => s.kind === "agent" && s.name === "review.reviewing")
938
- expect(reviewing?.kind === "agent" ? reviewing.prompt : "").toContain("base: c0")
940
+ const composing = h.steps.find((s) => s.kind === "run" && s.name === "review.composing")
941
+ expect(composing?.kind === "run" ? composing.body : "").toContain("<!-- base: c0 -->")
939
942
  })
940
943
 
941
944
  it("names the entry commit in every lens prompt, on the first lap and after a feedback lap", async () => {
@@ -1192,10 +1195,6 @@ describe("reviewedRefactor's tail prompts", () => {
1192
1195
  it.each([
1193
1196
  ["refactor.build.fix", { findings: true, reds: 2 }],
1194
1197
  ["refactor.build.fix.quality.fixing", { findings: true }],
1195
- [
1196
- "refactor.build.review.fix.risks.fixing",
1197
- { firstReviewNote: "Risk: drops the carry", notes: [undefined] },
1198
- ],
1199
1198
  [
1200
1199
  "refactor.build.review.fix.nits.fixing",
1201
1200
  { notes: ["nit"], answers: { "note-1": { answer: "nit", p: 0.9 } } },
@@ -1211,17 +1210,3 @@ describe("reviewedRefactor's tail prompts", () => {
1211
1210
  },
1212
1211
  )
1213
1212
  })
1214
-
1215
- describe("reviewedRefactor's review lap wording", () => {
1216
- it("says the whole refactor since it started on the first and the second round", async () => {
1217
- const h = await driveReviewed(shape(), { notes: ["add — rename it", undefined] })
1218
- const prompts = h.steps.flatMap((s) =>
1219
- s.kind === "agent" && s.name === "review.reviewing" ? [s.prompt] : [],
1220
- )
1221
- expect(prompts).toHaveLength(2)
1222
- for (const prompt of prompts) {
1223
- expect(prompt).toContain("it covers the whole refactor since it started, on every round")
1224
- expect(prompt).not.toContain("only what is new since the previous review")
1225
- }
1226
- })
1227
- })
@@ -389,7 +389,6 @@ export const reviewedRefactor = async (
389
389
  fixAccess: strayAccess(p.strays),
390
390
  lensBase: entry,
391
391
  rules: t.refactorRules(p.strays, p.pattern),
392
- lap: "refactor",
393
392
  })
394
393
  if (outcome.verdict === "signoff") return true
395
394
  await reUnwind(outcome)
@@ -0,0 +1,179 @@
1
+ @inmem
2
+ Feature: every note in the review is answered with one tick
3
+
4
+ Each note gtd writes to `.gtd/REVIEW.md` ends in three boxes — fix as
5
+ suggested, won't fix, or the human's own answer written over the
6
+ placeholder. The gate refuses to land until every note holds exactly one
7
+ tick. A fix goes to the nit batch, a won't-fix is dropped and recorded in
8
+ the gate's commit, an own answer is judged like any other note. Nothing is
9
+ deferred to `.gtd/TODO.md`.
10
+
11
+ Background:
12
+ Given the shipped workflows, as gtd install scaffolds them
13
+ And an environment variable "GTD_QUALITYREVIEWS" set to "correctness"
14
+ And an environment variable "GTD_FLAGMODE" set to "false"
15
+ And a file "src/calc.ts" with:
16
+ """
17
+ export const add = (a: number, b: number) => a + b
18
+ """
19
+ And the working tree is committed as "feat: add calculator"
20
+ And a file "TODO.md" with:
21
+ """
22
+ # Add subtract
23
+
24
+ subtract(a, b) returns the difference.
25
+ """
26
+ And step "unwind" changes nothing
27
+ And step "start-gate.check" changes nothing
28
+ And step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
29
+ """
30
+ # Requirements
31
+
32
+ ## Concerns
33
+
34
+ ### Subtract
35
+
36
+ - `subtract(a, b)` returns `a - b`.
37
+
38
+ ## Acceptance Criteria
39
+
40
+ - AC-1: subtract(a, b) returns a - b.
41
+ """
42
+ And step "design.gate.answer" changes nothing
43
+ And step "seam.naive" writes "src/calc.test.ts" with:
44
+ """
45
+ it("[AC-1] subtracts", () => {})
46
+ """
47
+ And step "seam.naive" writes "src/calc.ts" with:
48
+ """
49
+ export const add = (a: number, b: number) => a + b
50
+ export const subtract = (a: number, b: number) => a - b
51
+ """
52
+ And step "seam.check" changes nothing
53
+ And step "implement.applying" runs its script
54
+ And step "implement.health.check" changes nothing
55
+ And step "implement.closing" runs its script
56
+ And judge step "implement.coverage" answers:
57
+ """
58
+ [{"id":"AC-1","answer":"yes","p":0.9}]
59
+ """
60
+ And step "build.quality.correctness.reviewing" writes ".gtd/QUALITY.md" with:
61
+ """
62
+ # Quality
63
+
64
+ ## subtract has no negative test
65
+
66
+ Add a test subtracting a larger number.
67
+
68
+ ## add could be a method
69
+
70
+ A class would read better.
71
+
72
+ ## AC-1 ignores floating point
73
+
74
+ Should subtract round? The criterion does not say.
75
+ """
76
+ And step "build.quality.sorting" runs its script
77
+ And step "build.review.composing" runs its script
78
+ And judge step "build.quality.triage" answers:
79
+ """
80
+ [{"id":"Q1","answer":"noise","p":0.9},{"id":"Q2","answer":"noise","p":0.9},{"id":"Q3","answer":"design","p":0.9}]
81
+ """
82
+ And step "build.review.closing" runs its script
83
+
84
+ Scenario: the note ends in its three answer boxes
85
+ When the process is driven
86
+ Then the process rests at "build.review.await-review"
87
+ And ".gtd/REVIEW.md" contains:
88
+ """
89
+ ## AC-1 ignores floating point
90
+
91
+ Should subtract round? The criterion does not say.
92
+
93
+ Tick exactly one:
94
+
95
+ - [ ] fix as suggested
96
+ - [ ] won't fix
97
+ - [ ] _your answer_
98
+ """
99
+
100
+ Scenario: a sign-off with the note unanswered is refused
101
+ When the process is driven
102
+ Then landing is refused with "answer-completeness: 1 note(s) in .gtd/REVIEW.md not answered"
103
+ And the process rests at "build.review.await-review"
104
+
105
+ Scenario: two ticks on one note are refused
106
+ When the process is driven
107
+ And the text "- [ ] fix as suggested" in ".gtd/REVIEW.md" is replaced with "- [x] fix as suggested"
108
+ And the text "- [ ] won't fix" in ".gtd/REVIEW.md" is replaced with "- [x] won't fix"
109
+ Then landing is refused with "tick exactly one box per note"
110
+
111
+ Scenario: a ticked answer still holding the placeholder is refused
112
+ When the process is driven
113
+ And the text "- [ ] _your answer_" in ".gtd/REVIEW.md" is replaced with "- [x] _your answer_"
114
+ Then landing is refused with "answer-completeness"
115
+
116
+ Scenario: won't fix drops the note, records it, and signs off
117
+ When the process is driven
118
+ And the text "- [ ] won't fix" in ".gtd/REVIEW.md" is replaced with "- [x] won't fix"
119
+ And gtd lands
120
+ And the process is driven
121
+ Then the process rests at "idle"
122
+ And the commit "gtd(human): build.review.await-review → build.review.closing" has a body containing "Gtd-Mark: wontfix=AC-1 ignores floating point"
123
+ And ".gtd/TODO.md" does not exist
124
+ And no commit body contains "build.review.triage"
125
+
126
+ Scenario: fix as suggested goes to the nit batch unjudged, and the note is not asked again
127
+ Given step "build.review.fix.nits.fixing" writes "src/calc.ts" with:
128
+ """
129
+ export const add = (a: number, b: number) => a + b
130
+ export const subtract = (a: number, b: number) => Math.round(a - b)
131
+ """
132
+ And step "build.review.fix.nits.fixing" is prompted with "Should subtract round?"
133
+ And step "build.health.check" changes nothing
134
+ When the process is driven
135
+ And the text "- [ ] fix as suggested" in ".gtd/REVIEW.md" is replaced with "- [x] fix as suggested"
136
+ And gtd lands
137
+ And the process is driven
138
+ Then the process rests at "build.review.await-review"
139
+ And no commit body contains "build.review.triage"
140
+ And ".gtd/REVIEW.md" contains "## Fixed from your notes"
141
+ And ".gtd/REVIEW.md" does not contain "AC-1 ignores floating point"
142
+ And ".gtd/TODO.md" does not exist
143
+ When gtd lands
144
+ And the process is driven
145
+ Then the process rests at "idle"
146
+
147
+ Scenario: an own answer is judged like a note
148
+ Given judge step "build.review.triage" answers:
149
+ """
150
+ [{"id":"answer-1","answer":"nit","p":0.9}]
151
+ """
152
+ And step "build.review.fix.nits.fixing" is prompted with "round half up"
153
+ And step "build.health.check" changes nothing
154
+ And step "build.review.fix.nits.fixing" writes "src/calc.ts" with:
155
+ """
156
+ export const add = (a: number, b: number) => a + b
157
+ export const subtract = (a: number, b: number) => Math.round(a - b)
158
+ """
159
+ When the process is driven
160
+ And the text "- [ ] _your answer_" in ".gtd/REVIEW.md" is replaced with "- [x] round half up"
161
+ And gtd lands
162
+ And the process is driven
163
+ Then the process rests at "build.review.await-review"
164
+ And the commit subjects end with:
165
+ """
166
+ gtd(human): build.review.await-review → build.review.triage
167
+ gtd(judge): build.review.triage → build.review.fix.nits.fixing
168
+ gtd(agent): build.review.fix.nits.fixing → build.health.check
169
+ gtd(check): build.health.check → build.review.closing
170
+ gtd(check): build.review.closing → build.review.composing
171
+ gtd(check): build.review.composing → build.review.await-review
172
+ """
173
+ And ".gtd/REVIEW.md" does not contain "AC-1 ignores floating point"
174
+
175
+ Scenario: deleting a note's boxes instead of answering is refused
176
+ When the process is driven
177
+ And the text "- [ ] fix as suggested" in ".gtd/REVIEW.md" is replaced with ""
178
+ And the text "Tick exactly one:" in ".gtd/REVIEW.md" is replaced with ""
179
+ Then landing is refused with "its answer boxes were deleted"
@@ -57,7 +57,7 @@ Feature: a feature process ends at the human review
57
57
  """
58
58
  [{"id":"AC-1","answer":"yes","p":0.9}]
59
59
  """
60
- And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
60
+ And step "build.review.composing" writes ".gtd/REVIEW.md" with:
61
61
  """
62
62
  # Review: abc1234
63
63
 
@@ -78,8 +78,8 @@ Feature: a feature process ends at the human review
78
78
  And the commit subjects end with:
79
79
  """
80
80
  gtd(judge): implement.coverage → implement.closing
81
- gtd(check): implement.closing → build.review.reviewing
82
- gtd(agent): build.review.reviewing → build.review.await-review
81
+ gtd(check): implement.closing → build.review.composing
82
+ gtd(check): build.review.composing → build.review.await-review
83
83
  """
84
84
 
85
85
  Scenario: a sign-off ends the process at idle
@@ -102,7 +102,7 @@ Feature: a feature process ends at the human review
102
102
  And ".gtd/REVIEW.md" does not exist
103
103
  And the commit subjects end with:
104
104
  """
105
- gtd(agent): build.review.reviewing → build.review.await-review
105
+ gtd(check): build.review.composing → build.review.await-review
106
106
  gtd(human): build.review.await-review → build.review.closing
107
107
  gtd(check): build.review.closing → idle
108
108
  """
@@ -214,8 +214,8 @@ Feature: a feature process ends at the human review
214
214
  gtd(agent): implement.building → implement.health.check
215
215
  gtd(check): implement.health.check → implement.coverage
216
216
  gtd(judge): implement.coverage → implement.closing
217
- gtd(check): implement.closing → build.review.reviewing
218
- gtd(agent): build.review.reviewing → build.review.await-review
217
+ gtd(check): implement.closing → build.review.composing
218
+ gtd(check): build.review.composing → build.review.await-review
219
219
  """
220
220
 
221
221
  Scenario: a design numbering new behaviour at or below an earlier ID is refused