@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.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +107 -53
- package/claude/hooks/sketch.ts +1 -1
- package/dist/chunks/{reserved-Ch4LLrEj.mjs → reserved-COEMFEpy.mjs} +84 -51
- package/dist/chunks/{steering-DVILanVf.mjs → steering-D4LUQ-av.mjs} +95 -12
- package/dist/chunks/tail-C_xn8U7U.mjs +246 -0
- package/dist/flows.mjs +11 -1
- package/dist/gtd.bundle.mjs +498 -30
- package/dist/steering.mjs +2 -2
- package/dist/testkit.mjs +460 -28
- package/dist/web/main.js +42 -13
- package/dist/workflow-kit.mjs +61 -25
- package/dist/workflows/cleanup.mjs +2 -2
- package/dist/workflows/feature.mjs +66 -57
- package/dist/workflows/fix.mjs +3 -3
- package/dist/workflows/review.mjs +2 -2
- package/dist/workflows/rollout.mjs +1 -1
- package/dist/workflows.mjs +446 -141
- package/package.json +1 -1
- package/src/cli/Cli.test.ts +33 -1
- package/src/cli/Cli.ts +70 -6
- package/src/cli/History.ts +15 -0
- package/src/cli/Judges.test.ts +373 -0
- package/src/cli/Judges.ts +624 -0
- package/src/cli/Metrics.ts +3 -16
- package/src/cli/Program.test.ts +3 -1
- package/src/cli/Program.ts +9 -0
- package/src/flows/scripts.ts +15 -0
- package/src/steering/index.ts +12 -1
- package/src/steering/review.test.ts +109 -20
- package/src/steering/review.ts +160 -9
- package/src/testkit/EmittedScriptRecognizer.ts +0 -14
- package/src/testkit/FlowScripts.test.ts +17 -0
- package/src/testkit/FlowScripts.ts +15 -0
- package/src/testkit/steps.ts +31 -0
- package/src/workflow-kit/review.test.ts +170 -26
- package/src/workflow-kit/review.ts +95 -19
- package/src/workflows/feature/coverage.feature +3 -3
- package/src/workflows/feature/fast-path.feature +2 -2
- package/src/workflows/feature/feature.test.ts +2 -37
- package/src/workflows/feature/feature.ts +12 -14
- package/src/workflows/feature/flag-mode.feature +2 -2
- package/src/workflows/feature/lens-review.feature +246 -0
- package/src/workflows/feature/one-step-land.feature +2 -2
- package/src/workflows/feature/quality-unresolved.feature +47 -32
- package/src/workflows/feature/refactor-absorbs.feature +3 -3
- package/src/workflows/feature/refactor-first.feature +5 -5
- package/src/workflows/feature/refactor-rebuild.feature +7 -7
- package/src/workflows/feature/refactor-review.feature +19 -100
- package/src/workflows/feature/refactor.test.ts +12 -27
- package/src/workflows/feature/refactor.ts +0 -1
- package/src/workflows/feature/review-answers.feature +179 -0
- package/src/workflows/feature/review-gate.feature +6 -6
- package/src/workflows/feature/review.test.ts +33 -77
- package/src/workflows/feature/review.ts +79 -47
- package/src/workflows/feature/seam-rejection.feature +2 -2
- package/src/workflows/feature/seam.feature +2 -2
- package/src/workflows/feature/seam.test.ts +1 -1
- package/src/workflows/feature/slicing.feature +6 -6
- package/src/workflows/feature/steps.test.ts +0 -12
- package/src/workflows/feature/steps.ts +3 -10
- package/src/workflows/index.ts +1 -0
- package/src/workflows/shared/__fixtures__/feature-collecting-prompt.txt +6 -5
- package/src/workflows/shared/access.test.ts +2 -11
- package/src/workflows/shared/access.ts +0 -2
- package/src/workflows/shared/lenses.test.ts +39 -0
- package/src/workflows/shared/lenses.ts +176 -0
- package/src/workflows/shared/options.ts +1 -0
- package/src/workflows/shared/tail.ts +19 -4
- package/src/workflows/shared/text.test.ts +106 -88
- package/src/workflows/shared/text.ts +164 -53
- package/src/workflows/shared/vars.ts +1 -0
- 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.
|
|
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.
|
|
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.
|
|
195
|
-
gtd(
|
|
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.
|
|
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.
|
|
349
|
-
gtd(
|
|
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.
|
|
519
|
-
gtd(
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
1188
|
-
gtd(
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
938
|
-
expect(
|
|
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.
|
|
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.
|
|
82
|
-
gtd(
|
|
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(
|
|
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.
|
|
218
|
-
gtd(
|
|
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
|