@pmelab/gtd 56.0.0 → 58.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 (56) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +29 -35
  3. package/dist/chunks/{reserved-B8EC-WE8.mjs → reserved-BzAFXuz_.mjs} +56 -131
  4. package/dist/chunks/{review-HdrX0FJ7.mjs → review-CVqRS0mc.mjs} +2 -2
  5. package/dist/chunks/{tail-BSLah2mA.mjs → tail-JQzB21Q3.mjs} +1 -1
  6. package/dist/workflows/cleanup.mjs +2 -2
  7. package/dist/workflows/feature.mjs +99 -170
  8. package/dist/workflows/fix.mjs +2 -2
  9. package/dist/workflows/review.mjs +3 -3
  10. package/dist/workflows/rollout.mjs +1 -1
  11. package/dist/workflows.mjs +150 -297
  12. package/package.json +1 -1
  13. package/src/workflows/feature/acceptance-criteria.feature +32 -0
  14. package/src/workflows/feature/criteria-coverage.feature +0 -2
  15. package/src/workflows/feature/criteria.test.ts +1 -41
  16. package/src/workflows/feature/criteria.ts +12 -18
  17. package/src/workflows/feature/fast-path.feature +4 -1
  18. package/src/workflows/feature/feature.test.ts +3 -39
  19. package/src/workflows/feature/feature.ts +6 -8
  20. package/src/workflows/feature/lens-models.feature +0 -2
  21. package/src/workflows/feature/lens-review.feature +0 -2
  22. package/src/workflows/feature/naive-acceptance.feature +4 -0
  23. package/src/workflows/feature/naive-test.feature +263 -0
  24. package/src/workflows/feature/one-step-land.feature +4 -1
  25. package/src/workflows/feature/planning.ts +2 -0
  26. package/src/workflows/feature/refactor-absorbs.feature +4 -1
  27. package/src/workflows/feature/refactor-first.feature +4 -1
  28. package/src/workflows/feature/refactor-lens-models.feature +4 -0
  29. package/src/workflows/feature/refactor-rebuild.feature +4 -1
  30. package/src/workflows/feature/refactor-review.feature +20 -1
  31. package/src/workflows/feature/release-flag.feature +167 -0
  32. package/src/workflows/feature/release-flag.test.ts +49 -0
  33. package/src/workflows/feature/release-flag.ts +46 -0
  34. package/src/workflows/feature/review-gate.feature +1 -3
  35. package/src/workflows/feature/reviewer-walkthrough.feature +0 -2
  36. package/src/workflows/feature/risk-tier.feature +32 -0
  37. package/src/workflows/feature/seam-rejection.feature +8 -1
  38. package/src/workflows/feature/seam.feature +8 -1
  39. package/src/workflows/feature/seam.test.ts +21 -9
  40. package/src/workflows/feature/seam.ts +60 -14
  41. package/src/workflows/feature/standards.feature +0 -2
  42. package/src/workflows/shared/options.test.ts +3 -10
  43. package/src/workflows/shared/options.ts +5 -6
  44. package/src/workflows/shared/prose.ts +0 -6
  45. package/src/workflows/shared/skills.test.ts +0 -4
  46. package/src/workflows/shared/skills.ts +0 -5
  47. package/src/workflows/shared/steps.ts +1 -1
  48. package/src/workflows/shared/text.test.ts +58 -69
  49. package/src/workflows/shared/text.ts +79 -162
  50. package/src/workflows/shared/vars.ts +2 -4
  51. package/src/workflows/feature/flag-mode.feature +0 -88
  52. package/src/workflows/feature/hands-on-skip.feature +0 -316
  53. package/src/workflows/feature/prototype-rounds.feature +0 -156
  54. package/src/workflows/feature/prototype.feature +0 -428
  55. package/src/workflows/feature/prototype.test.ts +0 -43
  56. package/src/workflows/feature/prototype.ts +0 -198
@@ -0,0 +1,263 @@
1
+ @inmem
2
+ Feature: a person tries the naive pass by hand before anything builds on it
3
+
4
+ `naiveTest` is a factory option of the shipped workflows, off by default. On,
5
+ every green naive pass is applied to the working tree and the process rests
6
+ at `seam.try`. A clean landing signs it off and the process goes on — to the
7
+ seam judge when the requirements ask for a release flag, else straight to the
8
+ implementation. Notes in
9
+ `.gtd/NAIVE-TEST.md`, a code edit or a requirements edit send it back: the
10
+ pass and the person's code edits leave the tree again, and the next naive
11
+ pass gets the notes and the edits. Every lap ends at the gate again.
12
+
13
+ Rule: with no release flag asked for
14
+
15
+ Background:
16
+ Given a gtd config with:
17
+ """
18
+ import { feature } from "@pmelab/gtd/workflows/feature"
19
+ export { summary, steering, skills, access } from "@pmelab/gtd/workflows/feature"
20
+ export default feature({ naiveTest: true })
21
+ """
22
+ And an environment variable "GTD_QUALITYREVIEWS" set to ""
23
+ And a file "src/calc.ts" with:
24
+ """
25
+ export const add = (a: number, b: number) => a + b
26
+ """
27
+ And the working tree is committed as "feat: add calculator"
28
+ And a file "TODO.md" with:
29
+ """
30
+ # Add subtract
31
+
32
+ subtract(a, b) returns the difference.
33
+ """
34
+ And step "unwind" changes nothing
35
+ And step "start-gate.check" changes nothing
36
+ And step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
37
+ """
38
+ # Requirements
39
+
40
+ ## Impact
41
+
42
+ - the calculator module
43
+
44
+ ## Acceptance Criteria
45
+
46
+ - AC-1: subtract(a, b) returns a - b.
47
+ """
48
+ And step "design.gate.answer" changes nothing
49
+ And step "seam.naive" writes "src/calc.test.ts" with:
50
+ """
51
+ it("[AC-1] subtracts", () => {})
52
+ """
53
+ And step "seam.naive" writes "src/calc.ts" with:
54
+ """
55
+ export const add = (a: number, b: number) => a + b
56
+ export const subtract = (a: number, b: number) => a + b
57
+ """
58
+ And step "seam.check" changes nothing
59
+ And step "seam.applying" runs its script
60
+ And step "seam.restoring" runs its script
61
+
62
+ Scenario: a green naive pass rests at seam.try, applied to the working tree
63
+ When the process is driven
64
+ Then the process rests at "seam.try"
65
+ And the resting step's content contains "try it by hand"
66
+ And the resting step's content contains "`.gtd/NAIVE-TEST.md`"
67
+ And "src/calc.ts" contains "export const subtract"
68
+ And the commit subjects end with:
69
+ """
70
+ gtd(agent): seam.naive → seam.check
71
+ gtd(check): seam.check → seam.applying
72
+ gtd(check): seam.applying → seam.try
73
+ """
74
+
75
+ Scenario: a clean landing signs the pass off, takes it out and lands it as the implementation
76
+ When the process is driven
77
+ Then the process rests at "seam.try"
78
+ When gtd lands
79
+ And step "implement.applying" runs its script
80
+ And step "implement.health.check" changes nothing
81
+ And step "implement.closing" runs its script
82
+ And the process is driven
83
+ Then the process rests at "build.review.reviewing"
84
+ And "src/calc.ts" contains "export const subtract"
85
+ And the commit subjects end with:
86
+ """
87
+ gtd(check): seam.applying → seam.try
88
+ gtd(human): seam.try → seam.restoring
89
+ gtd(check): seam.restoring → implement.applying
90
+ gtd(check): implement.applying → implement.health.check
91
+ gtd(check): implement.health.check → implement.closing
92
+ gtd(check): implement.closing → build.review.reviewing
93
+ """
94
+
95
+ Scenario: notes and a code edit send the pass back, out of the tree, to a naive pass that reads both
96
+ Given step "seam.naive", when prompted with "> subtract(5, 3) printed 8, not 2.", writes "notes-read.txt" with:
97
+ """
98
+ read
99
+ """
100
+ And step "seam.naive", when prompted with "-- . ':(exclude).gtd'", writes "edits-read.txt" with:
101
+ """
102
+ read
103
+ """
104
+ When the process is driven
105
+ Then the process rests at "seam.try"
106
+ Given a file ".gtd/NAIVE-TEST.md" with:
107
+ """
108
+ subtract(5, 3) printed 8, not 2.
109
+ """
110
+ And a file "src/calc.ts" with:
111
+ """
112
+ export const add = (a: number, b: number) => a + b
113
+ export const subtract = (a: number, b: number) => a - b
114
+ """
115
+ And a file "src/hint.ts" with:
116
+ """
117
+ export const hint = "subtract, not add"
118
+ """
119
+ When gtd lands
120
+ And the process is driven
121
+ Then the process rests at "seam.try"
122
+ And "src/hint.ts" does not exist
123
+ And "notes-read.txt" contains "read"
124
+ And "edits-read.txt" contains "read"
125
+ And ".gtd/NAIVE-TEST.md" does not exist
126
+ And the commit subjects end with:
127
+ """
128
+ gtd(check): seam.applying → seam.try
129
+ gtd(human): seam.try → seam.restoring
130
+ gtd(check): seam.restoring → seam.naive
131
+ gtd(agent): seam.naive → seam.check
132
+ gtd(check): seam.check → seam.applying
133
+ gtd(check): seam.applying → seam.try
134
+ """
135
+
136
+ Scenario: notes alone send the pass back with no edits to read
137
+ Given step "seam.naive", when prompted with "They edited the code", writes "edits-read.txt" with:
138
+ """
139
+ read
140
+ """
141
+ When the process is driven
142
+ Then the process rests at "seam.try"
143
+ Given a file ".gtd/NAIVE-TEST.md" with:
144
+ """
145
+ subtract adds.
146
+ """
147
+ When gtd lands
148
+ And the process is driven
149
+ Then the process rests at "seam.try"
150
+ And "edits-read.txt" does not exist
151
+
152
+ Scenario: a requirements edit at seam.try stays, and sends the pass back
153
+ When the process is driven
154
+ Then the process rests at "seam.try"
155
+ Given a file ".gtd/REQUIREMENTS.md" with:
156
+ """
157
+ # Requirements
158
+
159
+ ## Impact
160
+
161
+ - the calculator module
162
+
163
+ ## Acceptance Criteria
164
+
165
+ - AC-1: subtract(a, b) returns a - b.
166
+ - AC-2: subtract(a, b) rejects NaN.
167
+ """
168
+ When gtd lands
169
+ And the process is driven
170
+ Then the process rests at "seam.try"
171
+ And ".gtd/REQUIREMENTS.md" contains "AC-2: subtract(a, b) rejects NaN."
172
+ And the commit subjects end with:
173
+ """
174
+ gtd(human): seam.try → seam.restoring
175
+ gtd(check): seam.restoring → seam.naive
176
+ gtd(agent): seam.naive → seam.check
177
+ gtd(check): seam.check → seam.applying
178
+ gtd(check): seam.applying → seam.try
179
+ """
180
+
181
+ Rule: with a release flag asked for
182
+
183
+ Background:
184
+ Given a gtd config with:
185
+ """
186
+ import { feature } from "@pmelab/gtd/workflows/feature"
187
+ export { summary, steering, skills, access } from "@pmelab/gtd/workflows/feature"
188
+ export default feature({ naiveTest: true })
189
+ """
190
+ And an environment variable "GTD_QUALITYREVIEWS" set to ""
191
+ And a file "src/calc.ts" with:
192
+ """
193
+ export const add = (a: number, b: number) => a + b
194
+ """
195
+ And the working tree is committed as "feat: add calculator"
196
+ And a file "TODO.md" with:
197
+ """
198
+ # Add subtract
199
+
200
+ subtract(a, b) returns the difference.
201
+ """
202
+ And step "unwind" changes nothing
203
+ And step "start-gate.check" changes nothing
204
+ And step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
205
+ """
206
+ # Requirements
207
+
208
+ ## Impact
209
+
210
+ - the calculator module
211
+
212
+ ## Release Flag
213
+
214
+ new
215
+
216
+ ## Acceptance Criteria
217
+
218
+ - AC-1: subtract(a, b) returns a - b.
219
+ """
220
+ And step "design.gate.answer" changes nothing
221
+ And step "seam.naive" writes "src/calc.test.ts" with:
222
+ """
223
+ it("[AC-1] subtracts", () => {})
224
+ """
225
+ And step "seam.naive" writes "src/calc.ts" with:
226
+ """
227
+ export const add = (a: number, b: number) => a + b
228
+ export const subtract = (a: number, b: number) => a + b
229
+ """
230
+ And step "seam.check" changes nothing
231
+ And step "seam.applying" runs its script
232
+ And step "seam.restoring" runs its script
233
+
234
+ Scenario: the person tries the pass before the seam judge rules
235
+ When the process is driven
236
+ Then the process rests at "seam.try"
237
+ And the resting step's content contains "the seam judge rules on its shape"
238
+ When gtd lands
239
+ And the process is driven
240
+ Then the process rests at "seam.judge"
241
+
242
+ Rule: with a naiveTest that is neither true nor false
243
+
244
+ Background:
245
+ Given an environment variable "GTD_NAIVETEST" set to "maybe"
246
+ And a gtd config with:
247
+ """
248
+ import { feature } from "@pmelab/gtd/workflows/feature"
249
+ export { summary, steering, skills, access } from "@pmelab/gtd/workflows/feature"
250
+ export default feature()
251
+ """
252
+ And a file "src/calc.ts" with:
253
+ """
254
+ export const add = (a: number, b: number) => a + b
255
+ """
256
+ And the working tree is committed as "feat: add calculator"
257
+ And a file "TODO.md" with:
258
+ """
259
+ # Add subtract
260
+ """
261
+
262
+ Scenario: the landing that would pin it is refused
263
+ Then driving the process is refused with "naiveTest must be"
@@ -10,7 +10,6 @@ Feature: a naive pass the judge rules land is itself the implementation
10
10
 
11
11
  Background:
12
12
  Given the shipped workflows, as gtd install scaffolds them
13
- And an environment variable "GTD_PROTOTYPEROUNDS" set to "0"
14
13
  And an environment variable "GTD_QUALITYREVIEWS" set to "correctness"
15
14
  And an environment variable "GTD_FLAG_RISK_TIER" set to "0"
16
15
  And a file "src/greeting.ts" with:
@@ -40,6 +39,10 @@ Feature: a naive pass the judge rules land is itself the implementation
40
39
 
41
40
  - the greeting module
42
41
 
42
+ ## Release Flag
43
+
44
+ new
45
+
43
46
  ## Acceptance Criteria
44
47
 
45
48
  - AC-1: the change behaves as described.
@@ -9,6 +9,7 @@ import {
9
9
  } from "../../flows/index.js"
10
10
  import { REQUIREMENTS } from "../shared/steps.js"
11
11
  import { requireCriteria, requireImpact } from "./criteria.js"
12
+ import { requireReleaseFlag } from "./release-flag.js"
12
13
  import { answerProductQuestions, triage } from "./steps.js"
13
14
 
14
15
  /**
@@ -34,6 +35,7 @@ export const design = (base: string, guard?: () => void): Promise<void> =>
34
35
  requireReplies(REQUIREMENTS)
35
36
  requireCriteria(REQUIREMENTS)
36
37
  requireImpact(REQUIREMENTS)
38
+ requireReleaseFlag(REQUIREMENTS)
37
39
  guard?.()
38
40
  } while (await noteGate(REQUIREMENTS, answerProductQuestions))
39
41
  })
@@ -10,7 +10,6 @@ Feature: a refactor that carried the whole feature still gets a quality lap over
10
10
 
11
11
  Background:
12
12
  Given the shipped workflows, as gtd install scaffolds them
13
- And an environment variable "GTD_PROTOTYPEROUNDS" set to "0"
14
13
  And an environment variable "GTD_QUALITYREVIEWS" set to "correctness"
15
14
  And an environment variable "GTD_REFACTORQUALITYREVIEWS" set to ""
16
15
  And an environment variable "GTD_FLAG_RISK_TIER" set to "0"
@@ -41,6 +40,10 @@ Feature: a refactor that carried the whole feature still gets a quality lap over
41
40
 
42
41
  - the greeting module
43
42
 
43
+ ## Release Flag
44
+
45
+ new
46
+
44
47
  ## Acceptance Criteria
45
48
 
46
49
  - AC-1: the change behaves as described.
@@ -9,7 +9,6 @@ Feature: a refactor-first judgment walks one fixed path to the review gate
9
9
 
10
10
  Background:
11
11
  Given the shipped workflows, as gtd install scaffolds them
12
- And an environment variable "GTD_PROTOTYPEROUNDS" set to "0"
13
12
  And an environment variable "GTD_QUALITYREVIEWS" set to ""
14
13
  And an environment variable "GTD_REFACTORQUALITYREVIEWS" set to ""
15
14
  And an environment variable "GTD_FLAG_RISK_TIER" set to "0"
@@ -40,6 +39,10 @@ Feature: a refactor-first judgment walks one fixed path to the review gate
40
39
 
41
40
  - the greeting module
42
41
 
42
+ ## Release Flag
43
+
44
+ new
45
+
43
46
  ## Acceptance Criteria
44
47
 
45
48
  - AC-1: the change behaves as described.
@@ -33,6 +33,10 @@ Feature: the refactor review's lenses take their model hints from refactorQualit
33
33
 
34
34
  - the greeting module
35
35
 
36
+ ## Release Flag
37
+
38
+ new
39
+
36
40
  ## Acceptance Criteria
37
41
 
38
42
  - AC-1: the change behaves as described.
@@ -11,7 +11,6 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
11
11
 
12
12
  Background:
13
13
  Given the shipped workflows, as gtd install scaffolds them
14
- And an environment variable "GTD_PROTOTYPEROUNDS" set to "0"
15
14
  And an environment variable "GTD_QUALITYREVIEWS" set to ""
16
15
  And an environment variable "GTD_REFACTORQUALITYREVIEWS" set to ""
17
16
  And an environment variable "GTD_FLAG_RISK_TIER" set to "0"
@@ -46,6 +45,10 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
46
45
 
47
46
  - the greeting module
48
47
 
48
+ ## Release Flag
49
+
50
+ new
51
+
49
52
  ## Acceptance Criteria
50
53
 
51
54
  - AC-1: subtract returns the difference.
@@ -9,7 +9,6 @@ Feature: the refactor is reviewed on its own before the feature is implemented
9
9
 
10
10
  Background:
11
11
  Given the shipped workflows, as gtd install scaffolds them
12
- And an environment variable "GTD_PROTOTYPEROUNDS" set to "0"
13
12
  And an environment variable "GTD_QUALITYREVIEWS" set to ""
14
13
  And an environment variable "GTD_FLAG_RISK_TIER" set to "0"
15
14
 
@@ -52,6 +51,10 @@ Feature: the refactor is reviewed on its own before the feature is implemented
52
51
 
53
52
  - the greeting module
54
53
 
54
+ ## Release Flag
55
+
56
+ new
57
+
55
58
  ## Acceptance Criteria
56
59
 
57
60
  - AC-1: the change behaves as described.
@@ -150,6 +153,10 @@ Feature: the refactor is reviewed on its own before the feature is implemented
150
153
 
151
154
  - the greeting module
152
155
 
156
+ ## Release Flag
157
+
158
+ new
159
+
153
160
  ## Acceptance Criteria
154
161
 
155
162
  - AC-1: the change behaves as described.
@@ -247,6 +254,10 @@ Feature: the refactor is reviewed on its own before the feature is implemented
247
254
 
248
255
  - the greeting module
249
256
 
257
+ ## Release Flag
258
+
259
+ new
260
+
250
261
  ## Acceptance Criteria
251
262
 
252
263
  - AC-1: the change behaves as described.
@@ -1194,6 +1205,10 @@ Feature: the refactor is reviewed on its own before the feature is implemented
1194
1205
 
1195
1206
  - the greeting module
1196
1207
 
1208
+ ## Release Flag
1209
+
1210
+ new
1211
+
1197
1212
  ## Acceptance Criteria
1198
1213
 
1199
1214
  - AC-1: the change behaves as described.
@@ -1319,6 +1334,10 @@ Feature: the refactor is reviewed on its own before the feature is implemented
1319
1334
 
1320
1335
  - the greeting module
1321
1336
 
1337
+ ## Release Flag
1338
+
1339
+ new
1340
+
1322
1341
  ## Acceptance Criteria
1323
1342
 
1324
1343
  - AC-1: the change behaves as described.
@@ -0,0 +1,167 @@
1
+ @inmem
2
+ Feature: a release flag only when the requirements ask for one
3
+
4
+ A change ships unflagged unless `.gtd/REQUIREMENTS.md` carries a
5
+ `## Release Flag` section — written by triage, or by the skip path's impact
6
+ turn, only when the sketch asks for a flag, and editable at the design gate.
7
+ Its first line is `new` (a new release flag) or `existing: <NAME>` (behind a
8
+ flag that already exists). Without it no seam judge or refactor runs and the
9
+ naive pass lands as the implementation; with it the seam judge rules on the
10
+ pass.
11
+
12
+ Background:
13
+ Given the shipped workflows, as gtd install scaffolds them
14
+ And an environment variable "GTD_QUALITYREVIEWS" set to ""
15
+ And an environment variable "GTD_FLAG_RISK_TIER" set to "0"
16
+ And a file "src/calc.ts" with:
17
+ """
18
+ export const add = (a: number, b: number) => a + b
19
+ """
20
+ And the working tree is committed as "feat: add calculator"
21
+ And step "unwind" changes nothing
22
+ And step "start-gate.check" changes nothing
23
+ And step "seam.naive" writes "src/calc.test.ts" with:
24
+ """
25
+ it("[AC-1] subtracts", () => {})
26
+ """
27
+ And step "seam.naive" writes "src/calc.ts" with:
28
+ """
29
+ export const add = (a: number, b: number) => a + b
30
+ export const subtract = (a: number, b: number) => a - b
31
+ """
32
+ And step "seam.check" changes nothing
33
+
34
+ Rule: the design path
35
+
36
+ Background:
37
+ Given a file "TODO.md" with:
38
+ """
39
+ # Add subtract
40
+
41
+ subtract(a, b) returns the difference.
42
+ """
43
+ And step "design.gate.answer" changes nothing
44
+
45
+ Scenario: with no Release Flag section the naive pass lands unjudged, and no flag is asked for
46
+ Given step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
47
+ """
48
+ # Requirements
49
+
50
+ ## Impact
51
+
52
+ - the calculator module
53
+
54
+ ## Acceptance Criteria
55
+
56
+ - AC-1: subtract(a, b) returns a - b.
57
+ """
58
+ And step "implement.applying" runs its script
59
+ And step "implement.health.check" changes nothing
60
+ And step "implement.closing" runs its script
61
+ When the process is driven
62
+ Then the process rests at "build.review.reviewing"
63
+ And "src/calc.ts" contains "subtract"
64
+ And no commit body contains "seam.judge"
65
+ And the commit subjects end with:
66
+ """
67
+ gtd(human): design.gate.answer → seam.naive
68
+ gtd(agent): seam.naive → seam.check
69
+ gtd(check): seam.check → implement.applying
70
+ gtd(check): implement.applying → implement.health.check
71
+ gtd(check): implement.health.check → implement.closing
72
+ gtd(check): implement.closing → build.review.reviewing
73
+ """
74
+
75
+ Scenario: a new release flag asked for sends the naive pass to the seam judge
76
+ Given step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
77
+ """
78
+ # Requirements
79
+
80
+ ## Impact
81
+
82
+ - the calculator module
83
+
84
+ ## Release Flag
85
+
86
+ new
87
+
88
+ ## Acceptance Criteria
89
+
90
+ - AC-1: subtract(a, b) returns a - b.
91
+ """
92
+ When the process is driven
93
+ Then the process rests at "seam.judge"
94
+
95
+ Scenario: an existing flag asked for sends the naive pass to the seam judge too
96
+ Given step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
97
+ """
98
+ # Requirements
99
+
100
+ ## Impact
101
+
102
+ - the calculator module
103
+
104
+ ## Release Flag
105
+
106
+ existing: GTD_FLAG_BETA
107
+
108
+ ## Acceptance Criteria
109
+
110
+ - AC-1: subtract(a, b) returns a - b.
111
+ """
112
+ When the process is driven
113
+ Then the process rests at "seam.judge"
114
+
115
+ Scenario: a Release Flag section that asks for neither is refused
116
+ Given step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
117
+ """
118
+ # Requirements
119
+
120
+ ## Impact
121
+
122
+ - the calculator module
123
+
124
+ ## Release Flag
125
+
126
+ maybe later
127
+
128
+ ## Acceptance Criteria
129
+
130
+ - AC-1: subtract(a, b) returns a - b.
131
+ """
132
+ Then driving the process is refused with "release-flag"
133
+
134
+ Rule: the skip path
135
+
136
+ Background:
137
+ Given a file "TODO.md" with:
138
+ """
139
+ # Add subtract
140
+
141
+ Ship it behind the existing GTD_FLAG_BETA flag.
142
+
143
+ ## Acceptance criteria
144
+
145
+ - subtract(a, b) returns a - b.
146
+ """
147
+ And judge step "design.clear" answers:
148
+ """
149
+ [{"id":"clear","answer":"yes","p":0.9}]
150
+ """
151
+ And step "design.normalise" runs its script
152
+
153
+ Scenario: the impact turn records the flag the sketch asks for, and the seam judge rules
154
+ Given step "design.impact" appends to ".gtd/REQUIREMENTS.md":
155
+ """
156
+
157
+ ## Impact
158
+
159
+ - the calculator module
160
+
161
+ ## Release Flag
162
+
163
+ existing: GTD_FLAG_BETA
164
+ """
165
+ When the process is driven
166
+ Then the process rests at "seam.judge"
167
+ And ".gtd/REQUIREMENTS.md" contains "existing: GTD_FLAG_BETA"
@@ -0,0 +1,49 @@
1
+ import { describe, expect, it } from "vitest"
2
+ import { releaseFlagOf } from "./release-flag.js"
3
+
4
+ const requirements = (section: string): string =>
5
+ `# Requirements\n\n## Impact\n\n- a module\n\n${section}## Acceptance Criteria\n\n- AC-1: a\n`
6
+
7
+ describe("releaseFlagOf", () => {
8
+ it("asks for no flag without the section, or with none", () => {
9
+ expect(releaseFlagOf(requirements(""))).toEqual({ kind: "none" })
10
+ expect(releaseFlagOf(requirements("## Release Flag\n\nnone\n\n"))).toEqual({ kind: "none" })
11
+ })
12
+
13
+ it("reads new and an existing flag's name, backticked or not", () => {
14
+ expect(releaseFlagOf(requirements("## Release Flag\n\nnew\n\n"))).toEqual({ kind: "new" })
15
+ for (const line of [
16
+ "existing: GTD_FLAG_BETA",
17
+ "existing: `GTD_FLAG_BETA`",
18
+ "Existing:GTD_FLAG_BETA",
19
+ ])
20
+ expect(releaseFlagOf(requirements(`## Release Flag\n\n${line}\n\n`))).toEqual({
21
+ kind: "existing",
22
+ name: "GTD_FLAG_BETA",
23
+ })
24
+ })
25
+
26
+ it("reads only the first line under the heading, and only a level-2 heading", () => {
27
+ expect(
28
+ releaseFlagOf(requirements("## Release Flag\n\nnew\n\nbecause the sketch says so\n\n")),
29
+ ).toEqual({
30
+ kind: "new",
31
+ })
32
+ expect(releaseFlagOf(requirements("### Release Flag\n\nnew\n\n"))).toEqual({ kind: "none" })
33
+ })
34
+
35
+ it("ignores a fenced heading", () => {
36
+ expect(releaseFlagOf(requirements("```\n## Release Flag\n\nnew\n```\n\n"))).toEqual({
37
+ kind: "none",
38
+ })
39
+ })
40
+
41
+ it("names the line it cannot read", () => {
42
+ expect(releaseFlagOf(requirements("## Release Flag\n\nmaybe later\n\n"))).toEqual({
43
+ unreadable: "maybe later",
44
+ })
45
+ expect(releaseFlagOf(requirements("## Release Flag\n\nexisting:\n\n"))).toEqual({
46
+ unreadable: "existing:",
47
+ })
48
+ })
49
+ })