@pmelab/gtd 34.0.0 → 36.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 (40) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +35 -26
  3. package/dist/chunks/{reserved-BcJgt5_R.mjs → reserved-BAv71I4i.mjs} +43 -10
  4. package/dist/chunks/{tail-CM_fa93v.mjs → tail-kar1zhOb.mjs} +1 -1
  5. package/dist/flows.mjs +15 -10
  6. package/dist/gtd.bundle.mjs +14 -9
  7. package/dist/testkit.mjs +43 -23
  8. package/dist/workflows/cleanup.mjs +2 -2
  9. package/dist/workflows/feature.mjs +97 -20
  10. package/dist/workflows/fix.mjs +2 -2
  11. package/dist/workflows/review.mjs +2 -2
  12. package/dist/workflows/rollout.mjs +1 -1
  13. package/dist/workflows.mjs +152 -38
  14. package/package.json +1 -1
  15. package/skills/authoring/SKILL.md +3 -3
  16. package/src/flows/scripts.ts +31 -9
  17. package/src/testkit/FlowScripts.test.ts +58 -0
  18. package/src/testkit/FlowScripts.ts +61 -24
  19. package/src/workflows/feature/acceptance-criteria.feature +5 -1
  20. package/src/workflows/feature/coverage.feature +164 -0
  21. package/src/workflows/feature/coverage.ts +106 -0
  22. package/src/workflows/feature/fast-path.feature +17 -20
  23. package/src/workflows/feature/feature.test.ts +25 -4
  24. package/src/workflows/feature/feature.ts +13 -9
  25. package/src/workflows/feature/flag-mode.feature +23 -10
  26. package/src/workflows/feature/lens-models.feature +11 -1
  27. package/src/workflows/feature/naive-acceptance.feature +2 -2
  28. package/src/workflows/feature/one-step-land.feature +16 -13
  29. package/src/workflows/feature/quality-unresolved.feature +11 -1
  30. package/src/workflows/feature/refactor-absorbs.feature +6 -1
  31. package/src/workflows/feature/refactor-first.feature +6 -1
  32. package/src/workflows/feature/refactor-review.feature +24 -0
  33. package/src/workflows/feature/risk-tier.feature +12 -4
  34. package/src/workflows/feature/seam-rejection.feature +10 -10
  35. package/src/workflows/feature/seam.feature +35 -27
  36. package/src/workflows/feature/seam.test.ts +12 -4
  37. package/src/workflows/feature/seam.ts +42 -32
  38. package/src/workflows/review/review-door.feature +18 -5
  39. package/src/workflows/shared/text.test.ts +8 -0
  40. package/src/workflows/shared/text.ts +54 -9
@@ -17,14 +17,15 @@ import * as t from "../shared/text.js"
17
17
  import { skipDesign, statedCriteria, type StatedCriteria } from "./criteria.js"
18
18
  import { design } from "./planning.js"
19
19
  import { buildTail, isCode, reUnwind, type ReviewOutcome } from "./review.js"
20
- import { implement, seamBuild, type SeamOutcome } from "./seam.js"
20
+ import { implement, seamBuild } from "./seam.js"
21
21
  import { recordRisk, riskTierOn } from "./tier.js"
22
22
 
23
23
  // The ordinary start. Any change to the tree starts a process: `idle` →
24
24
  // `unwind` reverts the sketch (its intent survives in history) → a
25
- // green-baseline gate → design → a judged naive pass (refactoring first when
26
- // the judge asks; with `flagMode` off, neither) → implement → the quality lap,
27
- // and the episode ends back at `idle`. Human review is the `review` door's.
25
+ // green-baseline gate → design → a naive pass, judged with `flagMode` on: it
26
+ // lands as the implementation, or (refactoring first when the judge asks) is
27
+ // built fresh from → the health loop → the quality lap, and the episode ends
28
+ // back at `idle`. Human review is the `review` door's.
28
29
 
29
30
  /** Revert the sketch that started the process out of the working tree; its intent survives in history. */
30
31
  export const unwind = (): Promise<void> => {
@@ -36,14 +37,17 @@ export const unwind = (): Promise<void> => {
36
37
 
37
38
  export { reUnwind }
38
39
 
39
- /** A judged naive pass (none with `flagMode` off), then implement and the quality lap; design must have run since `firstBase`. */
40
+ /** A naive pass (judged only with `flagMode` on), then implement and the quality lap; design must have run since `firstBase`. */
40
41
  export const buildFeature = async (firstBase: string): Promise<void> => {
41
42
  const tier = riskTierOn() ? recordRisk() : undefined
42
- const seam: Omit<SeamOutcome, "reference"> & { reference?: string } = flagModeOn()
43
- ? await seamBuild(firstBase)
44
- : { base: firstBase }
43
+ const seam = await seamBuild(firstBase)
45
44
  await slice("feature", async () => {
46
- await implement({ reference: seam.reference, tier, afterRefactor: seam.refactored })
45
+ await implement({
46
+ reference: seam.reference,
47
+ tier,
48
+ afterRefactor: seam.refactored,
49
+ naive: seam.land === true ? seam.reference : undefined,
50
+ })
47
51
  // An empty feature slice: the refactor carried the feature, so the lap covers the whole change.
48
52
  const base =
49
53
  seam.refactored === true && !changesSince(seam.base).some((c) => isCode(c.path))
@@ -1,9 +1,9 @@
1
1
  @inmem
2
- Feature: flag mode off builds a feature with no release flag, seam judge or refactor
2
+ Feature: flag mode off lands the naive pass with no release flag, seam judge or refactor
3
3
 
4
4
  `flagMode` is a factory option of the shipped workflows, on by default. Off,
5
5
  the project ships without feature flags: no seam judge and no refactor run,
6
- and the naive implementation goes straight through the health loop and the
6
+ and the naive pass itself lands, straight through the health loop and the
7
7
  quality lap.
8
8
 
9
9
  Background:
@@ -43,23 +43,33 @@ Feature: flag mode off builds a feature with no release flag, seam judge or refa
43
43
  """
44
44
  And step "design.gate.answer" changes nothing
45
45
 
46
- Scenario: flag mode off skips the seam judge and the refactor, and asks for no flag
46
+ Scenario: flag mode off lands the naive pass unjudged, and asks for no flag
47
47
  When the process is driven
48
- Then the process rests at "implement.building"
48
+ Then the process rests at "seam.naive"
49
49
  And the resting step's content contains "the quickest way that works"
50
- And the resting step's content contains "Add no release flag — this project ships without release flags"
51
- And the resting step's content does not contain "new release flag"
52
- Given step "implement.building" writes "src/calc.ts" with:
50
+ And the resting step's content does not contain "release flag"
51
+ Given step "seam.naive" writes "src/calc.test.ts" with:
52
+ """
53
+ it("[AC-1] subtracts", () => {})
54
+ """
55
+ And step "seam.naive" writes "src/calc.ts" with:
53
56
  """
54
57
  export const add = (a: number, b: number) => a + b
55
58
  export const subtract = (a: number, b: number) => a - b
56
59
  """
60
+ And step "seam.check" changes nothing
61
+ And step "implement.applying" runs its script
57
62
  And step "implement.health.check" changes nothing
58
63
  And step "implement.closing" runs its script
64
+ And judge step "implement.coverage" answers:
65
+ """
66
+ [{"id":"AC-1","answer":"yes","p":0.9}]
67
+ """
59
68
  And step "build.quality.correctness.reviewing" changes nothing
60
69
  When the process is driven
61
70
  Then the process rests at "idle"
62
71
  And "src/calc.ts" contains "subtract"
72
+ And "src/calc.test.ts" contains "[AC-1] subtracts"
63
73
  And the commit subjects end with:
64
74
  """
65
75
  chore: initial commit
@@ -68,9 +78,12 @@ Feature: flag mode off builds a feature with no release flag, seam judge or refa
68
78
  gtd(check): unwind → start-gate.check
69
79
  gtd(check): start-gate.check → design.triage
70
80
  gtd(agent): design.triage → design.gate.answer
71
- gtd(human): design.gate.answer → implement.building
72
- gtd(agent): implement.building → implement.health.check
73
- gtd(check): implement.health.check → implement.closing
81
+ gtd(human): design.gate.answer → seam.naive
82
+ gtd(agent): seam.naive → seam.check
83
+ gtd(check): seam.check → implement.applying
84
+ gtd(check): implement.applying → implement.health.check
85
+ gtd(check): implement.health.check → implement.coverage
86
+ gtd(judge): implement.coverage → implement.closing
74
87
  gtd(check): implement.closing → build.quality.correctness.reviewing
75
88
  gtd(agent): build.quality.correctness.reviewing → idle
76
89
  """
@@ -37,13 +37,23 @@ Feature: each quality lens runs on its own model hint
37
37
  - AC-1: `subtract(a, b)` returns `a - b`.
38
38
  """
39
39
  And step "design.gate.answer" changes nothing
40
- And step "implement.building" writes "src/calc.ts" with:
40
+ And step "seam.naive" writes "src/calc.test.ts" with:
41
+ """
42
+ it("[AC-1] subtracts", () => {})
43
+ """
44
+ And step "seam.naive" writes "src/calc.ts" with:
41
45
  """
42
46
  export const add = (a: number, b: number) => a + b
43
47
  export const subtract = (a: number, b: number) => a - b
44
48
  """
49
+ And step "seam.check" changes nothing
50
+ And step "implement.applying" runs its script
45
51
  And step "implement.health.check" changes nothing
46
52
  And step "implement.closing" runs its script
53
+ And judge step "implement.coverage" answers:
54
+ """
55
+ [{"id":"AC-1","answer":"yes","p":0.9}]
56
+ """
47
57
 
48
58
  Scenario: a hinted lens runs on its hint, every other lens on its default
49
59
  When the process is driven
@@ -129,12 +129,12 @@ Feature: a naive pass ends only when a test names every criterion and the suite
129
129
  """
130
130
  And step "seam.check" from now on changes nothing
131
131
  When the process is driven
132
- Then the process rests at "implement.building"
132
+ Then the process rests at "implement.applying"
133
133
  And the commit subjects end with:
134
134
  """
135
135
  gtd(human): design.gate.answer → seam.naive
136
136
  gtd(agent): seam.naive → seam.check
137
137
  gtd(check): seam.check → seam.naive
138
138
  gtd(agent): seam.naive → seam.check
139
- gtd(check): seam.check → implement.building
139
+ gtd(check): seam.check → implement.applying
140
140
  """
@@ -1,11 +1,11 @@
1
1
  # One SDLC path per file, so a changed path reds exactly one fixture — do not merge.
2
2
  @inmem
3
- Feature: a naive pass the judge rules land goes straight to implement with no seam gate
3
+ Feature: a naive pass the judge rules land is itself the implementation
4
4
 
5
5
  With GTD_FLAG_RISK_TIER off, a naive pass that
6
6
  edits an existing source file is judged land: the process skips the approval
7
- gate and any refactor, and runs implement and quality
8
- back to idle, with no review. The flag is pinned here so the per-flag test runs never
7
+ gate and any refactor, applies the kept pass as it is — no build turn — and
8
+ runs the health loop and quality back to idle, with no review. The flag is pinned here so the per-flag test runs never
9
9
  move it off this path.
10
10
 
11
11
  Background:
@@ -53,18 +53,20 @@ Feature: a naive pass the judge rules land goes straight to implement with no se
53
53
  """
54
54
  [{"id":"shape","answer":"land","p":0.9}]
55
55
  """
56
- And step "implement.building" writes "src/greeting.ts" with:
57
- """
58
- export const greeting = "Hello, world!"
59
- """
56
+ And step "implement.applying" runs its script
60
57
  And step "implement.health.check" changes nothing
61
58
  And step "implement.closing" runs its script
59
+ And judge step "implement.coverage" answers:
60
+ """
61
+ [{"id":"AC-1","answer":"yes","p":0.9}]
62
+ """
62
63
  And step "build.quality.correctness.reviewing" changes nothing
63
64
 
64
- Scenario: a land judgment runs idle to idle with no seam gate or refactor
65
+ Scenario: a land judgment applies the naive pass and runs idle to idle with no rebuild
65
66
  When the process is driven
66
67
  Then the process rests at "idle"
67
- And "src/greeting.ts" contains "Hello, world!"
68
+ And "src/greeting.ts" contains "Hello, world"
69
+ And "src/acceptance.test.ts" contains "[AC-1] holds"
68
70
  And the commit subjects end with:
69
71
  """
70
72
  gtd(human): idle → unwind
@@ -74,15 +76,16 @@ Feature: a naive pass the judge rules land goes straight to implement with no se
74
76
  gtd(human): design.gate.answer → seam.naive
75
77
  gtd(agent): seam.naive → seam.check
76
78
  gtd(check): seam.check → seam.judge
77
- gtd(judge): seam.judge → implement.building
78
- gtd(agent): implement.building → implement.health.check
79
- gtd(check): implement.health.check → implement.closing
79
+ gtd(judge): seam.judge → implement.applying
80
+ gtd(check): implement.applying → implement.health.check
81
+ gtd(check): implement.health.check → implement.coverage
82
+ gtd(judge): implement.coverage → implement.closing
80
83
  gtd(check): implement.closing → build.quality.correctness.reviewing
81
84
  gtd(agent): build.quality.correctness.reviewing → idle
82
85
  """
83
86
  And the commit "gtd(human): idle → unwind" has a body containing "Gtd-Var: flag_risk_tier=0"
84
87
  And the commit "gtd(agent): seam.naive → seam.check" has a body containing "Gtd-Kept:"
85
- And the commit "gtd(judge): seam.judge → implement.building" has a body containing "\"answer\":\"land\""
88
+ And the commit "gtd(judge): seam.judge → implement.applying" has a body containing "\"answer\":\"land\""
86
89
  And no commit body contains "Gtd-Approved:"
87
90
  And the output lines of gtd "slices" start with:
88
91
  """
@@ -37,13 +37,23 @@ Feature: quality findings left unresolved hold a feature process short of idle
37
37
  - AC-1: subtract(a, b) returns a - b.
38
38
  """
39
39
  And step "design.gate.answer" changes nothing
40
- And step "implement.building" writes "src/calc.ts" with:
40
+ And step "seam.naive" writes "src/calc.test.ts" with:
41
+ """
42
+ it("[AC-1] subtracts", () => {})
43
+ """
44
+ And step "seam.naive" writes "src/calc.ts" with:
41
45
  """
42
46
  export const add = (a: number, b: number) => a + b
43
47
  export const subtract = (a: number, b: number) => a - b
44
48
  """
49
+ And step "seam.check" changes nothing
50
+ And step "implement.applying" runs its script
45
51
  And step "implement.health.check" changes nothing
46
52
  And step "implement.closing" runs its script
53
+ And judge step "implement.coverage" answers:
54
+ """
55
+ [{"id":"AC-1","answer":"yes","p":0.9}]
56
+ """
47
57
 
48
58
  Scenario: findings the fix cap left unresolved rest at build.quality-unresolved
49
59
  Given step "build.quality.correctness.reviewing" writes ".gtd/QUALITY.md" with:
@@ -94,6 +94,10 @@ Feature: a refactor that carried the whole feature still gets a quality lap over
94
94
  And step "implement.building" changes nothing
95
95
  And step "implement.health.check" changes nothing
96
96
  And step "implement.closing" runs its script
97
+ And judge step "implement.coverage" answers:
98
+ """
99
+ [{"id":"AC-1","answer":"yes","p":0.9}]
100
+ """
97
101
  When gtd lands
98
102
  And the process is driven
99
103
  Then the process rests at "build.quality.correctness.reviewing"
@@ -109,7 +113,8 @@ Feature: a refactor that carried the whole feature still gets a quality lap over
109
113
  gtd(human): refactor.build.review.await-review → refactor.build.review.closing
110
114
  gtd(check): refactor.build.review.closing → implement.building
111
115
  gtd(agent): implement.building → implement.health.check
112
- gtd(check): implement.health.check → implement.closing
116
+ gtd(check): implement.health.check → implement.coverage
117
+ gtd(judge): implement.coverage → implement.closing
113
118
  gtd(check): implement.closing → build.quality.correctness.reviewing
114
119
  gtd(agent): build.quality.correctness.reviewing → idle
115
120
  """
@@ -108,6 +108,10 @@ Feature: a refactor-first judgment walks one fixed path to idle
108
108
  """
109
109
  And step "implement.health.check" changes nothing
110
110
  And step "implement.closing" runs its script
111
+ And judge step "implement.coverage" answers:
112
+ """
113
+ [{"id":"AC-1","answer":"yes","p":0.9}]
114
+ """
111
115
  When the process is driven
112
116
  Then the process rests at "idle"
113
117
  And "src/calc.ts" contains "op(a, b, 1)"
@@ -130,7 +134,8 @@ Feature: a refactor-first judgment walks one fixed path to idle
130
134
  gtd(human): refactor.build.review.await-review → refactor.build.review.closing
131
135
  gtd(check): refactor.build.review.closing → implement.building
132
136
  gtd(agent): implement.building → implement.health.check
133
- gtd(check): implement.health.check → implement.closing
137
+ gtd(check): implement.health.check → implement.coverage
138
+ gtd(judge): implement.coverage → implement.closing
134
139
  gtd(check): implement.closing → idle
135
140
  """
136
141
  And the commit "gtd(human): idle → unwind" has a body containing "Gtd-Var: flag_risk_tier=0"
@@ -347,6 +347,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
347
347
  """
348
348
  And step "implement.health.check" changes nothing
349
349
  And step "implement.closing" runs its script
350
+ And judge step "implement.coverage" answers:
351
+ """
352
+ [{"id":"AC-1","answer":"yes","p":0.9}]
353
+ """
350
354
  When the process is driven
351
355
  Then the process rests at "refactor.build.review.await-review"
352
356
  Given a file ".gtd/REVIEW.md" with:
@@ -636,6 +640,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
636
640
  """
637
641
  And step "implement.health.check" changes nothing
638
642
  And step "implement.closing" runs its script
643
+ And judge step "implement.coverage" answers:
644
+ """
645
+ [{"id":"AC-1","answer":"yes","p":0.9}]
646
+ """
639
647
  When the process is driven
640
648
  Then the process rests at "refactor.build.review.await-review"
641
649
  Given a file ".gtd/REVIEW.md" with:
@@ -711,6 +719,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
711
719
  """
712
720
  And step "implement.health.check" changes nothing
713
721
  And step "implement.closing" runs its script
722
+ And judge step "implement.coverage" answers:
723
+ """
724
+ [{"id":"AC-1","answer":"yes","p":0.9}]
725
+ """
714
726
  When the process is driven
715
727
  Then the process rests at "refactor.build.review.await-review"
716
728
  Given a file ".gtd/REVIEW.md" with:
@@ -973,6 +985,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
973
985
  """
974
986
  And step "implement.health.check" changes nothing
975
987
  And step "implement.closing" runs its script
988
+ And judge step "implement.coverage" answers:
989
+ """
990
+ [{"id":"AC-1","answer":"yes","p":0.9}]
991
+ """
976
992
  When the process is driven
977
993
  Then the process rests at "refactor.build.review.await-review"
978
994
  Given a file ".gtd/REVIEW.md" with:
@@ -1052,6 +1068,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
1052
1068
  """
1053
1069
  And step "implement.health.check" changes nothing
1054
1070
  And step "implement.closing" runs its script
1071
+ And judge step "implement.coverage" answers:
1072
+ """
1073
+ [{"id":"AC-1","answer":"yes","p":0.9}]
1074
+ """
1055
1075
  When the process is driven
1056
1076
  Then the process rests at "refactor.build.review.await-review"
1057
1077
  Given a file ".gtd/REVIEW.md" with:
@@ -1226,6 +1246,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
1226
1246
  """
1227
1247
  And step "implement.health.check" changes nothing
1228
1248
  And step "implement.closing" runs its script
1249
+ And judge step "implement.coverage" answers:
1250
+ """
1251
+ [{"id":"AC-1","answer":"yes","p":0.9}]
1252
+ """
1229
1253
  When the process is driven
1230
1254
  Then the process rests at "refactor.build.review.await-review"
1231
1255
  Given a file ".gtd/REVIEW.md" with:
@@ -133,7 +133,7 @@ Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_T
133
133
  | low |
134
134
  | high |
135
135
 
136
- Scenario: the tier comes from the requirements the final design gate lap accepted
136
+ Scenario: the tier a rebuilt pass is told comes from the requirements the final design gate lap accepted
137
137
  Given step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
138
138
  """
139
139
  # Requirements
@@ -146,7 +146,11 @@ Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_T
146
146
 
147
147
  - AC-1: the change behaves as described.
148
148
  """
149
- And step "seam.check" changes nothing
149
+ And step "seam.check" writes "src/acceptance.test.ts" with:
150
+ """
151
+ it("[AC-1] holds elsewhere", () => {})
152
+ """
153
+ And step "implement.applying" runs its script
150
154
  And step "seam.naive" writes "src/acceptance.test.ts" with:
151
155
  """
152
156
  it("[AC-1] holds", () => {})
@@ -245,7 +249,7 @@ Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_T
245
249
  And the resting step's content does not contain "## Production Signals"
246
250
 
247
251
 
248
- Scenario: the flag-off twin keeps today's flag demand
252
+ Scenario: the flag-off twin keeps today's flag demand on a rebuilt pass
249
253
  Given step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
250
254
  """
251
255
  # Requirements
@@ -259,7 +263,11 @@ Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_T
259
263
  - AC-1: the change behaves as described.
260
264
  """
261
265
  And step "design.gate.answer" changes nothing
262
- And step "seam.check" changes nothing
266
+ And step "seam.check" writes "src/acceptance.test.ts" with:
267
+ """
268
+ it("[AC-1] holds elsewhere", () => {})
269
+ """
270
+ And step "implement.applying" runs its script
263
271
  And step "seam.naive" writes "src/acceptance.test.ts" with:
264
272
  """
265
273
  it("[AC-1] holds", () => {})
@@ -52,6 +52,10 @@ Feature: rejected naive passes walk one fixed path through the steer gate to idl
52
52
  """
53
53
  And step "implement.health.check" changes nothing
54
54
  And step "implement.closing" runs its script
55
+ And judge step "implement.coverage" answers:
56
+ """
57
+ [{"id":"AC-1","answer":"yes","p":0.9}]
58
+ """
55
59
  When the process is driven
56
60
  Then the process rests at "seam.judge"
57
61
 
@@ -93,12 +97,7 @@ Feature: rejected naive passes walk one fixed path through the steer gate to idl
93
97
  """
94
98
  [{"id":"shape","answer":"land","p":0.9}]
95
99
  """
96
- And step "implement.building" writes "src/calc.ts" with:
97
- """
98
- export const add = (a: number, b: number) => a + b
99
- export const subtract = (a: number, b: number) => a - b
100
- export const SUBTRACT = true
101
- """
100
+ And step "implement.applying" runs its script
102
101
  When gtd lands
103
102
  And the process is driven
104
103
  Then the process rests at "idle"
@@ -121,16 +120,17 @@ Feature: rejected naive passes walk one fixed path through the steer gate to idl
121
120
  gtd(human): seam.steer → seam.naive
122
121
  gtd(agent): seam.naive → seam.check
123
122
  gtd(check): seam.check → seam.judge
124
- gtd(judge): seam.judge → implement.building
125
- gtd(agent): implement.building → implement.health.check
126
- gtd(check): implement.health.check → implement.closing
123
+ gtd(judge): seam.judge → implement.applying
124
+ gtd(check): implement.applying → implement.health.check
125
+ gtd(check): implement.health.check → implement.coverage
126
+ gtd(judge): implement.coverage → implement.closing
127
127
  gtd(check): implement.closing → idle
128
128
  """
129
129
  And the commit "gtd(human): idle → unwind" has a body containing "Gtd-Var: flag_risk_tier=0"
130
130
  And the commit "gtd(agent): seam.naive → seam.check" has a body containing "Gtd-Kept:"
131
131
  And the commit "gtd(judge): seam.judge → seam.naive" has a body containing "\"answer\":\"reject\""
132
132
  And the commit "gtd(judge): seam.judge → seam.steer" has a body containing "\"answer\":\"reject\""
133
- And the commit "gtd(judge): seam.judge → implement.building" has a body containing "\"answer\":\"land\""
133
+ And the commit "gtd(judge): seam.judge → implement.applying" has a body containing "\"answer\":\"land\""
134
134
  And no commit body contains "Gtd-Approved:"
135
135
  And the output lines of gtd "slices" start with:
136
136
  """
@@ -2,8 +2,8 @@
2
2
  Feature: the naive pass and seam judge decide how a feature is built
3
3
 
4
4
  After design a naive pass is set aside under a kept ref, the judge reads its
5
- diff, and the process either implements straight away, refactors the seam
6
- first behind a human approval, or retries the naive pass.
5
+ diff, and the process either applies the pass as the implementation,
6
+ refactors the seam first behind a human approval, or retries the naive pass.
7
7
 
8
8
  Background:
9
9
  Given the shipped workflows, as gtd install scaffolds them
@@ -50,7 +50,7 @@ Feature: the naive pass and seam judge decide how a feature is built
50
50
  """
51
51
  And step "design.gate.answer" changes nothing
52
52
 
53
- Scenario: a land judgment goes straight to the implementation with no seam gate or refactor
53
+ Scenario: a land judgment applies the naive pass with no seam gate, refactor or build turn
54
54
  Given step "seam.check" changes nothing
55
55
  And step "seam.naive" writes "src/acceptance.test.ts" with:
56
56
  """
@@ -66,7 +66,7 @@ Feature: the naive pass and seam judge decide how a feature is built
66
66
  [{"id":"shape","answer":"land","p":0.9}]
67
67
  """
68
68
  When the process is driven
69
- Then the process rests at "implement.building"
69
+ Then the process rests at "implement.applying"
70
70
  And the last commit body contains "Gtd-Judge:"
71
71
  And the commit subjects end with:
72
72
  """
@@ -79,27 +79,34 @@ Feature: the naive pass and seam judge decide how a feature is built
79
79
  gtd(human): design.gate.answer → seam.naive
80
80
  gtd(agent): seam.naive → seam.check
81
81
  gtd(check): seam.check → seam.judge
82
- gtd(judge): seam.judge → implement.building
82
+ gtd(judge): seam.judge → implement.applying
83
83
  """
84
84
 
85
- Scenario: config skills for the implement scope reach the implement step
86
- Given step "seam.check" changes nothing
87
- And step "seam.naive" writes "src/acceptance.test.ts" with:
85
+ Scenario: a naive pass that no longer applies is built fresh, with the implement scope's skills
86
+ Given step "seam.naive" writes "src/acceptance.test.ts" with:
88
87
  """
89
88
  it("[AC-1] holds", () => {})
90
89
  """
91
- And step "seam.naive" writes "src/calc.ts" with:
90
+ And step "seam.naive" writes "src/subtract.ts" with:
92
91
  """
93
- export const add = (a: number, b: number) => a + b
94
92
  export const subtract = (a: number, b: number) => a - b
95
93
  """
96
- And judge step "seam.judge" answers:
94
+ And step "seam.check" writes "src/subtract.ts" with:
97
95
  """
98
- [{"id":"shape","answer":"land","p":0.9}]
96
+ export const subtract = (a: number, b: number) => b - a
99
97
  """
98
+ And step "implement.applying" runs its script
100
99
  When the process is driven
101
100
  Then the process rests at "implement.building"
102
101
  And the resting step's content contains "my-tdd, my-runbook"
102
+ And the resting step's content contains "git show"
103
+ And ".gtd/FEEDBACK.md" contains "could not apply the naive pass"
104
+ And "src/subtract.ts" contains "b - a"
105
+ And the commit subjects end with:
106
+ """
107
+ gtd(check): seam.check → implement.applying
108
+ gtd(check): implement.applying → implement.building
109
+ """
103
110
 
104
111
  Scenario: the naive pass lands as a marker commit and its turn stays off the branch
105
112
  Given step "seam.check" changes nothing
@@ -122,7 +129,7 @@ Feature: the naive pass and seam judge decide how a feature is built
122
129
  And the commit "gtd(agent): seam.naive → seam.check" has a body containing "Gtd-Kept:"
123
130
  And "src/calc.ts" does not contain "subtract"
124
131
 
125
- Scenario: the implementation is one build turn, a green check, then the requirements are closed out
132
+ Scenario: the implementation is the applied naive pass, a green check, then the requirements are closed out
126
133
  Given step "seam.check" changes nothing
127
134
  And step "seam.naive" writes "src/acceptance.test.ts" with:
128
135
  """
@@ -137,21 +144,22 @@ Feature: the naive pass and seam judge decide how a feature is built
137
144
  """
138
145
  [{"id":"shape","answer":"land","p":0.9}]
139
146
  """
140
- And step "implement.building" writes "src/calc.ts" with:
141
- """
142
- export const add = (a: number, b: number) => a + b
143
- export const subtract = (a: number, b: number) => a - b
144
- export const SUBTRACT_ENABLED = process.env.GTD_FLAG_SUBTRACT === "1"
145
- """
147
+ And step "implement.applying" runs its script
146
148
  And step "implement.health.check" changes nothing
147
149
  And step "implement.closing" runs its script
150
+ And judge step "implement.coverage" answers:
151
+ """
152
+ [{"id":"AC-1","answer":"yes","p":0.9}]
153
+ """
148
154
  When the process is driven
149
155
  Then the process rests at "idle"
156
+ And "src/calc.ts" contains "subtract"
150
157
  And the commit subjects end with:
151
158
  """
152
- gtd(judge): seam.judge → implement.building
153
- gtd(agent): implement.building → implement.health.check
154
- gtd(check): implement.health.check → implement.closing
159
+ gtd(judge): seam.judge → implement.applying
160
+ gtd(check): implement.applying → implement.health.check
161
+ gtd(check): implement.health.check → implement.coverage
162
+ gtd(judge): implement.coverage → implement.closing
155
163
  gtd(check): implement.closing → idle
156
164
  """
157
165
  And ".gtd/REQUIREMENTS.md" does not exist
@@ -172,12 +180,12 @@ Feature: the naive pass and seam judge decide how a feature is built
172
180
  it("adds", () => expect(2 + 2).toBe(4))
173
181
  """
174
182
  When the process is driven
175
- Then the process rests at "implement.building"
183
+ Then the process rests at "implement.applying"
176
184
  And the commit subjects end with:
177
185
  """
178
186
  gtd(human): design.gate.answer → seam.naive
179
187
  gtd(agent): seam.naive → seam.check
180
- gtd(check): seam.check → implement.building
188
+ gtd(check): seam.check → implement.applying
181
189
  """
182
190
 
183
191
  Scenario: a naive pass adding a glob-named file does not hide a modified sibling
@@ -253,7 +261,7 @@ Feature: the naive pass and seam judge decide how a feature is built
253
261
  gtd(judge): seam.judge → seam.steer
254
262
  """
255
263
 
256
- Scenario: a clean landing at the steer gate overrules, with no seam gate and no refactor
264
+ Scenario: a clean landing at the steer gate overrules and applies the pass, with no seam gate and no refactor
257
265
  Given step "seam.check" changes nothing
258
266
  And step "seam.naive" writes "src/acceptance.test.ts" with:
259
267
  """
@@ -270,9 +278,9 @@ Feature: the naive pass and seam judge decide how a feature is built
270
278
  When the process is driven
271
279
  Then the process rests at "seam.steer"
272
280
  When gtd lands
273
- Then the process rests at "implement.building"
281
+ Then the process rests at "implement.applying"
274
282
  And the commit subjects end with:
275
283
  """
276
284
  gtd(judge): seam.judge → seam.steer
277
- gtd(human): seam.steer → implement.building
285
+ gtd(human): seam.steer → implement.applying
278
286
  """
@@ -321,13 +321,19 @@ const driveSeam = async (
321
321
  }
322
322
 
323
323
  describe("seamBuild", () => {
324
- it("land resolves the kept tip with the caller's base and enters no slice", async () => {
324
+ it("land resolves the kept tip to land, with the caller's base, and enters no slice", async () => {
325
325
  const h = await driveSeam("land")
326
- expect(h.outcome).toEqual({ reference: "abc", base: "c-base" })
326
+ expect(h.outcome).toEqual({ reference: "abc", base: "c-base", land: true })
327
327
  expect(h.slices).toEqual([])
328
328
  expect(h.names).toEqual(["seam.naive", "seam.check", "seam.judge"])
329
329
  })
330
330
 
331
+ it("with flagMode off resolves a vetted pass to land with no judge", async () => {
332
+ const h = await driveSeam("reject", undefined, { flagMode: "false" })
333
+ expect(h.outcome).toEqual({ reference: "abc", base: "c-base", land: true })
334
+ expect(h.names).toEqual(["seam.naive", "seam.check"])
335
+ })
336
+
331
337
  it("a red check retries the pass, and the judge sees it only once green", async () => {
332
338
  const h = await driveSeam("land", undefined, {}, 1)
333
339
  expect(h.names).toEqual(["seam.naive", "seam.check", "seam.naive", "seam.check", "seam.judge"])
@@ -355,7 +361,7 @@ describe("seamBuild", () => {
355
361
  "seam.clear",
356
362
  "seam.judge",
357
363
  ])
358
- expect(h.outcome).toEqual({ reference: "abc", base: "c-base" })
364
+ expect(h.outcome).toEqual({ reference: "abc", base: "c-base", land: true })
359
365
  })
360
366
 
361
367
  it("refactor-first runs the reviewed refactor in slice refactor and resolves HEAD after it", async () => {
@@ -417,7 +423,9 @@ describe("implement", () => {
417
423
  {
418
424
  step: (request: StepRequest) => {
419
425
  requests.push(request)
420
- return Promise.resolve()
426
+ return Promise.resolve(
427
+ request.kind === "judge" ? { answers: {}, truncated: [] } : undefined,
428
+ )
421
429
  },
422
430
  pushScope: () => undefined,
423
431
  popScope: () => undefined,