@pmelab/gtd 30.0.0 → 31.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 +23 -9
- package/claude/hooks/register.tsx +5 -0
- package/dist/chunks/{reserved-iG86IR3I.mjs → reserved-CHTJTzpA.mjs} +68 -9
- package/dist/chunks/{tail-DA2UuJNP.mjs → tail-CCsDBbZe.mjs} +1 -1
- package/dist/workflows/cleanup.mjs +2 -2
- package/dist/workflows/feature.mjs +141 -11
- package/dist/workflows/fix.mjs +2 -2
- package/dist/workflows/review.mjs +2 -2
- package/dist/workflows/rollout.mjs +1 -1
- package/dist/workflows.mjs +207 -18
- package/package.json +1 -1
- package/src/workflows/feature/acceptance-criteria-tier.feature +25 -0
- package/src/workflows/feature/acceptance-criteria.feature +189 -0
- package/src/workflows/feature/criteria.test.ts +106 -0
- package/src/workflows/feature/criteria.ts +168 -0
- package/src/workflows/feature/fast-path.feature +4 -0
- package/src/workflows/feature/feature.test.ts +81 -10
- package/src/workflows/feature/feature.ts +18 -10
- package/src/workflows/feature/flag-mode.feature +165 -0
- package/src/workflows/feature/index.ts +1 -0
- package/src/workflows/feature/one-step-land.feature +4 -0
- package/src/workflows/feature/planning.ts +2 -0
- package/src/workflows/feature/refactor-absorbs.feature +4 -0
- package/src/workflows/feature/refactor-first.feature +4 -0
- package/src/workflows/feature/refactor-review.feature +24 -0
- package/src/workflows/feature/risk-tier.feature +32 -0
- package/src/workflows/feature/seam-rejection.feature +8 -0
- package/src/workflows/feature/seam.feature +8 -0
- package/src/workflows/feature/seam.ts +14 -7
- package/src/workflows/feature/tier-pin.feature +4 -0
- package/src/workflows/index.ts +1 -0
- package/src/workflows/shared/options.test.ts +12 -0
- package/src/workflows/shared/options.ts +17 -2
- package/src/workflows/shared/text.test.ts +16 -0
- package/src/workflows/shared/text.ts +90 -8
- package/src/workflows/shared/vars.ts +1 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
@inmem
|
|
2
|
+
Feature: flag mode off builds a feature with no release flag, seam judge or refactor
|
|
3
|
+
|
|
4
|
+
`flagMode` is a factory option of the shipped workflows, on by default. Off,
|
|
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
|
|
7
|
+
quality lap.
|
|
8
|
+
|
|
9
|
+
Background:
|
|
10
|
+
Given a gtd config with:
|
|
11
|
+
"""
|
|
12
|
+
import { feature } from "@pmelab/gtd/workflows/feature"
|
|
13
|
+
export { summary, steering, skills, access } from "@pmelab/gtd/workflows/feature"
|
|
14
|
+
export default feature({ flagMode: false })
|
|
15
|
+
"""
|
|
16
|
+
And an environment variable "GTD_QUALITYREVIEWS" set to "correctness"
|
|
17
|
+
And a file "src/calc.ts" with:
|
|
18
|
+
"""
|
|
19
|
+
export const add = (a: number, b: number) => a + b
|
|
20
|
+
"""
|
|
21
|
+
And the working tree is committed as "feat: add calculator"
|
|
22
|
+
And a file "TODO.md" with:
|
|
23
|
+
"""
|
|
24
|
+
# Add subtract
|
|
25
|
+
|
|
26
|
+
subtract(a, b) returns the difference.
|
|
27
|
+
"""
|
|
28
|
+
And step "unwind" changes nothing
|
|
29
|
+
And step "start-gate.check" changes nothing
|
|
30
|
+
And step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
|
|
31
|
+
"""
|
|
32
|
+
# Requirements
|
|
33
|
+
|
|
34
|
+
## Concerns
|
|
35
|
+
|
|
36
|
+
### Subtract
|
|
37
|
+
|
|
38
|
+
- `subtract(a, b)` returns `a - b`.
|
|
39
|
+
|
|
40
|
+
## Acceptance Criteria
|
|
41
|
+
|
|
42
|
+
- AC-1: the change behaves as described.
|
|
43
|
+
"""
|
|
44
|
+
And step "design.gate.answer" changes nothing
|
|
45
|
+
|
|
46
|
+
Scenario: flag mode off skips the seam judge and the refactor, and asks for no flag
|
|
47
|
+
When the process is driven
|
|
48
|
+
Then the process rests at "implement.building"
|
|
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:
|
|
53
|
+
"""
|
|
54
|
+
export const add = (a: number, b: number) => a + b
|
|
55
|
+
export const subtract = (a: number, b: number) => a - b
|
|
56
|
+
"""
|
|
57
|
+
And step "implement.health.check" changes nothing
|
|
58
|
+
And step "implement.closing" runs its script
|
|
59
|
+
And step "build.quality.correctness.reviewing" changes nothing
|
|
60
|
+
When the process is driven
|
|
61
|
+
Then the process rests at "build.review.reviewing"
|
|
62
|
+
And "src/calc.ts" contains "subtract"
|
|
63
|
+
And the commit subjects end with:
|
|
64
|
+
"""
|
|
65
|
+
chore: initial commit
|
|
66
|
+
feat: add calculator
|
|
67
|
+
gtd(human): idle → unwind
|
|
68
|
+
gtd(check): unwind → start-gate.check
|
|
69
|
+
gtd(check): start-gate.check → design.triage
|
|
70
|
+
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
|
|
74
|
+
gtd(check): implement.closing → build.quality.correctness.reviewing
|
|
75
|
+
gtd(agent): build.quality.correctness.reviewing → build.review.reviewing
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
Scenario: flag mode off asks for no flag on a feedback lap either
|
|
79
|
+
Given step "implement.building" writes "src/calc.ts" with:
|
|
80
|
+
"""
|
|
81
|
+
export const add = (a: number, b: number) => a + b
|
|
82
|
+
export const subtract = (a: number, b: number) => a - b
|
|
83
|
+
"""
|
|
84
|
+
And step "implement.health.check" changes nothing
|
|
85
|
+
And step "implement.closing" runs its script
|
|
86
|
+
And step "build.quality.correctness.reviewing" changes nothing
|
|
87
|
+
And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
|
|
88
|
+
"""
|
|
89
|
+
# Review: abc1234
|
|
90
|
+
|
|
91
|
+
<!-- base: 0000000 -->
|
|
92
|
+
|
|
93
|
+
## calc
|
|
94
|
+
|
|
95
|
+
- [ ] ./src/calc.ts#2-2
|
|
96
|
+
new subtract function
|
|
97
|
+
"""
|
|
98
|
+
When the process is driven
|
|
99
|
+
Then the process rests at "build.review.await-review"
|
|
100
|
+
Given a file ".gtd/REVIEW.md" with:
|
|
101
|
+
"""
|
|
102
|
+
# Review: abc1234
|
|
103
|
+
|
|
104
|
+
<!-- base: 0000000 -->
|
|
105
|
+
|
|
106
|
+
## calc
|
|
107
|
+
|
|
108
|
+
- [ ] ./src/calc.ts#2-2
|
|
109
|
+
new subtract function[^why]
|
|
110
|
+
|
|
111
|
+
[^why]:
|
|
112
|
+
- H: also export multiply
|
|
113
|
+
"""
|
|
114
|
+
And step "build.review.collecting" writes ".gtd/REQUIREMENTS.md" with:
|
|
115
|
+
"""
|
|
116
|
+
# Requirements
|
|
117
|
+
|
|
118
|
+
## Concerns
|
|
119
|
+
|
|
120
|
+
### Multiply
|
|
121
|
+
|
|
122
|
+
- Export `multiply()`.
|
|
123
|
+
|
|
124
|
+
## Acceptance Criteria
|
|
125
|
+
|
|
126
|
+
- AC-1: the change behaves as described.
|
|
127
|
+
"""
|
|
128
|
+
And step "build.review.collecting" writes ".gtd/REVIEW.md" with:
|
|
129
|
+
"""
|
|
130
|
+
# Review: abc1234
|
|
131
|
+
|
|
132
|
+
<!-- base: 0000000 -->
|
|
133
|
+
|
|
134
|
+
## calc
|
|
135
|
+
|
|
136
|
+
- [ ] ./src/calc.ts#2-2
|
|
137
|
+
new subtract function[^why]
|
|
138
|
+
|
|
139
|
+
[^why]:
|
|
140
|
+
- H: also export multiply
|
|
141
|
+
- A: noted in the requirements.
|
|
142
|
+
"""
|
|
143
|
+
When gtd lands
|
|
144
|
+
And the process is driven
|
|
145
|
+
Then the process rests at "build.review.await-review"
|
|
146
|
+
Given a file ".gtd/REVIEW.md" with:
|
|
147
|
+
"""
|
|
148
|
+
# Review: abc1234
|
|
149
|
+
|
|
150
|
+
<!-- base: 0000000 -->
|
|
151
|
+
|
|
152
|
+
## calc
|
|
153
|
+
|
|
154
|
+
- [ ] ./src/calc.ts#2-2
|
|
155
|
+
new subtract function
|
|
156
|
+
"""
|
|
157
|
+
And step "build.review.closing" runs its script
|
|
158
|
+
And step "re-unwind" runs its script
|
|
159
|
+
And step "implement.building" is no longer scripted
|
|
160
|
+
When gtd lands
|
|
161
|
+
And the process is driven
|
|
162
|
+
Then the process rests at "implement.building"
|
|
163
|
+
And the resting step's content contains "Add no release flag — this project ships without release flags"
|
|
164
|
+
And the resting step's content does not contain "release flag the earlier lap added"
|
|
165
|
+
And no commit body contains "Gtd-Kept:"
|
|
@@ -34,6 +34,10 @@ Feature: a naive pass the judge rules land goes straight to implement with no se
|
|
|
34
34
|
### Typo
|
|
35
35
|
|
|
36
36
|
- greeting reads "Hello, world".
|
|
37
|
+
|
|
38
|
+
## Acceptance Criteria
|
|
39
|
+
|
|
40
|
+
- AC-1: the change behaves as described.
|
|
37
41
|
"""
|
|
38
42
|
And step "design.gate.answer" changes nothing
|
|
39
43
|
And step "seam.naive" writes "src/greeting.ts" with:
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
scope,
|
|
9
9
|
} from "../../flows/index.js"
|
|
10
10
|
import { REQUIREMENTS } from "../shared/steps.js"
|
|
11
|
+
import { requireCriteria } from "./criteria.js"
|
|
11
12
|
import { answerProductQuestions, triage } from "./steps.js"
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -31,5 +32,6 @@ export const design = (base: string): Promise<void> =>
|
|
|
31
32
|
await triage(base)
|
|
32
33
|
requireProgress(REQUIREMENTS)
|
|
33
34
|
requireReplies(REQUIREMENTS)
|
|
35
|
+
requireCriteria(REQUIREMENTS)
|
|
34
36
|
} while (await noteGate(REQUIREMENTS, answerProductQuestions))
|
|
35
37
|
})
|
|
@@ -35,6 +35,10 @@ Feature: a refactor that carried the whole feature still gets a feature review
|
|
|
35
35
|
### Subtract
|
|
36
36
|
|
|
37
37
|
- `subtract(a, b)` returns `a - b`.
|
|
38
|
+
|
|
39
|
+
## Acceptance Criteria
|
|
40
|
+
|
|
41
|
+
- AC-1: the change behaves as described.
|
|
38
42
|
"""
|
|
39
43
|
And step "design.gate.answer" changes nothing
|
|
40
44
|
|
|
@@ -34,6 +34,10 @@ Feature: a refactor-first judgment walks one fixed path to idle
|
|
|
34
34
|
### Subtract
|
|
35
35
|
|
|
36
36
|
- `subtract(a, b)` returns `a - b`.
|
|
37
|
+
|
|
38
|
+
## Acceptance Criteria
|
|
39
|
+
|
|
40
|
+
- AC-1: the change behaves as described.
|
|
37
41
|
"""
|
|
38
42
|
And step "design.gate.answer" changes nothing
|
|
39
43
|
|
|
@@ -46,6 +46,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
46
46
|
### Subtract
|
|
47
47
|
|
|
48
48
|
- `subtract(a, b)` returns `a - b`.
|
|
49
|
+
|
|
50
|
+
## Acceptance Criteria
|
|
51
|
+
|
|
52
|
+
- AC-1: the change behaves as described.
|
|
49
53
|
"""
|
|
50
54
|
And step "design.gate.answer" changes nothing
|
|
51
55
|
And step "seam.naive" writes "src/calc.ts" with:
|
|
@@ -126,6 +130,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
126
130
|
### Subtract
|
|
127
131
|
|
|
128
132
|
- `subtract(a, b)` returns `a - b`.
|
|
133
|
+
|
|
134
|
+
## Acceptance Criteria
|
|
135
|
+
|
|
136
|
+
- AC-1: the change behaves as described.
|
|
129
137
|
"""
|
|
130
138
|
And step "design.gate.answer" changes nothing
|
|
131
139
|
And step "seam.naive" writes "src/calc.ts" with:
|
|
@@ -205,6 +213,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
205
213
|
### Subtract
|
|
206
214
|
|
|
207
215
|
- `subtract(a, b)` returns `a - b`.
|
|
216
|
+
|
|
217
|
+
## Acceptance Criteria
|
|
218
|
+
|
|
219
|
+
- AC-1: the change behaves as described.
|
|
208
220
|
"""
|
|
209
221
|
And step "design.gate.answer" changes nothing
|
|
210
222
|
And step "seam.naive" writes "src/calc.ts" with:
|
|
@@ -449,6 +461,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
449
461
|
# Requirements
|
|
450
462
|
|
|
451
463
|
- multiply, designed
|
|
464
|
+
|
|
465
|
+
## Acceptance Criteria
|
|
466
|
+
|
|
467
|
+
- AC-1: the change behaves as described.
|
|
452
468
|
"""
|
|
453
469
|
And step "implement.building" writes "src/calc.ts" with:
|
|
454
470
|
"""
|
|
@@ -1404,6 +1420,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
1404
1420
|
### Subtract
|
|
1405
1421
|
|
|
1406
1422
|
- `subtract(a, b)` returns `a - b`.
|
|
1423
|
+
|
|
1424
|
+
## Acceptance Criteria
|
|
1425
|
+
|
|
1426
|
+
- AC-1: the change behaves as described.
|
|
1407
1427
|
"""
|
|
1408
1428
|
And step "design.gate.answer" changes nothing
|
|
1409
1429
|
And step "seam.naive" writes "src/calc.ts" with:
|
|
@@ -1582,6 +1602,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
1582
1602
|
### Subtract
|
|
1583
1603
|
|
|
1584
1604
|
- `subtract(a, b)` returns `a - b`.
|
|
1605
|
+
|
|
1606
|
+
## Acceptance Criteria
|
|
1607
|
+
|
|
1608
|
+
- AC-1: the change behaves as described.
|
|
1585
1609
|
"""
|
|
1586
1610
|
And step "design.gate.answer" changes nothing
|
|
1587
1611
|
And judge step "seam.judge" answers:
|
|
@@ -49,6 +49,10 @@ Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_T
|
|
|
49
49
|
## Risk Tier
|
|
50
50
|
|
|
51
51
|
low — trivial copy change
|
|
52
|
+
|
|
53
|
+
## Acceptance Criteria
|
|
54
|
+
|
|
55
|
+
- AC-1: the change behaves as described.
|
|
52
56
|
"""
|
|
53
57
|
And step "design.gate.answer" changes nothing
|
|
54
58
|
When the process is driven
|
|
@@ -64,6 +68,10 @@ Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_T
|
|
|
64
68
|
## Risk Tier
|
|
65
69
|
|
|
66
70
|
high — touches payments
|
|
71
|
+
|
|
72
|
+
## Acceptance Criteria
|
|
73
|
+
|
|
74
|
+
- AC-1: the change behaves as described.
|
|
67
75
|
"""
|
|
68
76
|
And step "design.gate.answer" changes nothing
|
|
69
77
|
When the process is driven
|
|
@@ -80,6 +88,10 @@ Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_T
|
|
|
80
88
|
## Concerns
|
|
81
89
|
|
|
82
90
|
### Subtract
|
|
91
|
+
|
|
92
|
+
## Acceptance Criteria
|
|
93
|
+
|
|
94
|
+
- AC-1: the change behaves as described.
|
|
83
95
|
"""
|
|
84
96
|
And step "design.gate.answer" changes nothing
|
|
85
97
|
When the process is driven
|
|
@@ -105,6 +117,10 @@ Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_T
|
|
|
105
117
|
|
|
106
118
|
- error rate on /subtract stays flat
|
|
107
119
|
- p95 latency
|
|
120
|
+
|
|
121
|
+
## Acceptance Criteria
|
|
122
|
+
|
|
123
|
+
- AC-1: the change behaves as described.
|
|
108
124
|
"""
|
|
109
125
|
And step "design.gate.answer" changes nothing
|
|
110
126
|
When the process is driven
|
|
@@ -125,6 +141,10 @@ Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_T
|
|
|
125
141
|
## Risk Tier
|
|
126
142
|
|
|
127
143
|
low — trivial copy change
|
|
144
|
+
|
|
145
|
+
## Acceptance Criteria
|
|
146
|
+
|
|
147
|
+
- AC-1: the change behaves as described.
|
|
128
148
|
"""
|
|
129
149
|
And step "seam.naive" writes "src/calc.ts" with:
|
|
130
150
|
"""
|
|
@@ -157,6 +177,10 @@ Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_T
|
|
|
157
177
|
## Concerns
|
|
158
178
|
|
|
159
179
|
### Subtract
|
|
180
|
+
|
|
181
|
+
## Acceptance Criteria
|
|
182
|
+
|
|
183
|
+
- AC-1: the change behaves as described.
|
|
160
184
|
"""
|
|
161
185
|
And step "design.gate.answer" changes nothing
|
|
162
186
|
When the process is driven
|
|
@@ -199,6 +223,10 @@ Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_T
|
|
|
199
223
|
## Production Signals
|
|
200
224
|
|
|
201
225
|
- error rate stays flat
|
|
226
|
+
|
|
227
|
+
## Acceptance Criteria
|
|
228
|
+
|
|
229
|
+
- AC-1: the change behaves as described.
|
|
202
230
|
"""
|
|
203
231
|
And step "design.gate.answer" changes nothing
|
|
204
232
|
When the process is driven
|
|
@@ -220,6 +248,10 @@ Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_T
|
|
|
220
248
|
## Risk Tier
|
|
221
249
|
|
|
222
250
|
low — trivial
|
|
251
|
+
|
|
252
|
+
## Acceptance Criteria
|
|
253
|
+
|
|
254
|
+
- AC-1: the change behaves as described.
|
|
223
255
|
"""
|
|
224
256
|
And step "design.gate.answer" changes nothing
|
|
225
257
|
And step "seam.naive" writes "src/calc.ts" with:
|
|
@@ -33,6 +33,10 @@ Feature: rejected naive passes walk one fixed path through the steer gate to idl
|
|
|
33
33
|
### Subtract
|
|
34
34
|
|
|
35
35
|
- `subtract(a, b)` returns `a - b`.
|
|
36
|
+
|
|
37
|
+
## Acceptance Criteria
|
|
38
|
+
|
|
39
|
+
- AC-1: the change behaves as described.
|
|
36
40
|
"""
|
|
37
41
|
And step "design.gate.answer" changes nothing
|
|
38
42
|
|
|
@@ -77,6 +81,10 @@ Feature: rejected naive passes walk one fixed path through the steer gate to idl
|
|
|
77
81
|
### Subtract
|
|
78
82
|
|
|
79
83
|
- `subtract(a, b)` returns `a - b`, in the calculator module.
|
|
84
|
+
|
|
85
|
+
## Acceptance Criteria
|
|
86
|
+
|
|
87
|
+
- AC-1: the change behaves as described.
|
|
80
88
|
"""
|
|
81
89
|
And step "seam.naive" from now on changes nothing
|
|
82
90
|
And step "seam.naive" writes "src/calc.ts" with:
|
|
@@ -43,6 +43,10 @@ Feature: the naive pass and seam judge decide how a feature is built
|
|
|
43
43
|
### Subtract
|
|
44
44
|
|
|
45
45
|
- `subtract(a, b)` returns `a - b`.
|
|
46
|
+
|
|
47
|
+
## Acceptance Criteria
|
|
48
|
+
|
|
49
|
+
- AC-1: the change behaves as described.
|
|
46
50
|
"""
|
|
47
51
|
And step "design.gate.answer" changes nothing
|
|
48
52
|
|
|
@@ -184,6 +188,10 @@ Feature: the naive pass and seam judge decide how a feature is built
|
|
|
184
188
|
### Subtract
|
|
185
189
|
|
|
186
190
|
- `subtract(a, b)` returns `a - b`, in a new module.
|
|
191
|
+
|
|
192
|
+
## Acceptance Criteria
|
|
193
|
+
|
|
194
|
+
- AC-1: the change behaves as described.
|
|
187
195
|
"""
|
|
188
196
|
When gtd lands
|
|
189
197
|
Then the process rests at "seam.naive"
|
|
@@ -16,7 +16,9 @@ import { healthy } from "../shared/health.js"
|
|
|
16
16
|
import { coder, FEEDBACK, REQUIREMENTS } from "../shared/steps.js"
|
|
17
17
|
import * as t from "../shared/text.js"
|
|
18
18
|
import { defaults } from "../shared/vars.js"
|
|
19
|
+
import { requireCriteria, requireCriteriaFrozen } from "./criteria.js"
|
|
19
20
|
import { refactorStrays, reviewedRefactor } from "./refactor.js"
|
|
21
|
+
import { flagModeOn } from "../shared/options.js"
|
|
20
22
|
import type { RiskTier } from "./tier.js"
|
|
21
23
|
|
|
22
24
|
/** Naive-pass retries after a `reject`; the next `reject` rests at `seam.steer`. */
|
|
@@ -71,6 +73,7 @@ export function implement(
|
|
|
71
73
|
options.tier,
|
|
72
74
|
options.amend,
|
|
73
75
|
options.afterRefactor,
|
|
76
|
+
flagModeOn(),
|
|
74
77
|
),
|
|
75
78
|
{
|
|
76
79
|
label: "Implementing",
|
|
@@ -79,13 +82,16 @@ export function implement(
|
|
|
79
82
|
...(options.afterRefactor === true ? { allowEmpty: true } : {}),
|
|
80
83
|
},
|
|
81
84
|
)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
requireCriteriaFrozen(REQUIREMENTS)
|
|
86
|
+
await healthy(
|
|
87
|
+
() =>
|
|
88
|
+
t.agentWithSkills("fix.suite.fixing", t.implementFixPrompt(), {
|
|
89
|
+
label: "Fixing the check",
|
|
90
|
+
file: FEEDBACK,
|
|
91
|
+
model: coder(),
|
|
92
|
+
system: t.builderSystem(),
|
|
93
|
+
}),
|
|
94
|
+
{ guard: () => requireCriteriaFrozen(REQUIREMENTS), guardRests: false },
|
|
89
95
|
)
|
|
90
96
|
await run("closing", removeScript([REQUIREMENTS]), { label: "Closing out the implementation" })
|
|
91
97
|
})
|
|
@@ -122,6 +128,7 @@ const decide = (): Promise<Decision> =>
|
|
|
122
128
|
})
|
|
123
129
|
// Any edit steers, with a fresh budget and no stale rejection; clean overrules.
|
|
124
130
|
if (changes().length === 0) return { reference: tip.hash }
|
|
131
|
+
requireCriteria(REQUIREMENTS)
|
|
125
132
|
rejection = undefined
|
|
126
133
|
retries = 0
|
|
127
134
|
}
|
|
@@ -33,6 +33,10 @@ Feature: a process keeps the risk tier setting it started with when GTD_FLAG_RIS
|
|
|
33
33
|
## Risk Tier
|
|
34
34
|
|
|
35
35
|
low — a new pure function
|
|
36
|
+
|
|
37
|
+
## Acceptance Criteria
|
|
38
|
+
|
|
39
|
+
- AC-1: the change behaves as described.
|
|
36
40
|
"""
|
|
37
41
|
|
|
38
42
|
Scenario: a process started with the flag off records no tier after the flag turns on
|
package/src/workflows/index.ts
CHANGED
|
@@ -21,6 +21,7 @@ export {
|
|
|
21
21
|
} from "./shared/tail.js"
|
|
22
22
|
export { lensesOf } from "../workflow-kit/index.js"
|
|
23
23
|
export * from "./feature/steps.js"
|
|
24
|
+
export * from "./feature/criteria.js"
|
|
24
25
|
export * from "./feature/planning.js"
|
|
25
26
|
export * from "./feature/refactor.js"
|
|
26
27
|
export * from "./feature/seam.js"
|
|
@@ -30,6 +30,18 @@ describe("the shipped workflow factories", () => {
|
|
|
30
30
|
})
|
|
31
31
|
})
|
|
32
32
|
|
|
33
|
+
it("default flagMode on and lay a boolean factory option over it as a string", () => {
|
|
34
|
+
expect(defaults.flagMode).toBe("true")
|
|
35
|
+
expect(configure(feature({ flagMode: false }))).toMatchObject({
|
|
36
|
+
ok: true,
|
|
37
|
+
build: { defaults: { flagMode: "false" } },
|
|
38
|
+
})
|
|
39
|
+
expect(configure(review({ flagMode: true }))).toMatchObject({
|
|
40
|
+
ok: true,
|
|
41
|
+
build: { defaults: { flagMode: "true" } },
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
33
45
|
it("declare flag_risk_tier off by default; it is no factory option", () => {
|
|
34
46
|
expect(Object.keys(ShippedOptions.fields)).not.toContain("flag_risk_tier")
|
|
35
47
|
})
|
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
type WorkflowBase,
|
|
6
6
|
type WorkflowDoors,
|
|
7
7
|
type WorkflowFactory,
|
|
8
|
+
refuse,
|
|
9
|
+
vars,
|
|
8
10
|
} from "../../flows/index.js"
|
|
9
11
|
import { defaultFlagRegistry, defaults, envDefaults } from "./vars.js"
|
|
10
12
|
|
|
@@ -23,18 +25,31 @@ export const ShippedOptions = Schema.Struct({
|
|
|
23
25
|
testCommand: setting,
|
|
24
26
|
plannerModel: setting,
|
|
25
27
|
coderModel: setting,
|
|
28
|
+
flagMode: Schema.optionalWith(Schema.Boolean, { exact: true }),
|
|
26
29
|
})
|
|
27
30
|
|
|
28
31
|
export type ShippedOptions = Schema.Schema.Encoded<typeof ShippedOptions>
|
|
29
32
|
|
|
30
33
|
const over = (
|
|
31
34
|
base: Readonly<Record<string, string>>,
|
|
32
|
-
options: Readonly<Record<string, string>>,
|
|
35
|
+
options: Readonly<Record<string, string | boolean>>,
|
|
33
36
|
): Record<string, string> => ({
|
|
34
37
|
...base,
|
|
35
|
-
...Object.fromEntries(
|
|
38
|
+
...Object.fromEntries(
|
|
39
|
+
Object.entries(options)
|
|
40
|
+
.filter(([name]) => Object.hasOwn(base, name))
|
|
41
|
+
.map(([name, value]) => [name, String(value)]),
|
|
42
|
+
),
|
|
36
43
|
})
|
|
37
44
|
|
|
45
|
+
/** The `flagMode` setting, pinned at process start. Anything but true/false fails rather than guess a side. */
|
|
46
|
+
export const flagModeOn = (): boolean => {
|
|
47
|
+
const value = vars.flagMode ?? defaults.flagMode!
|
|
48
|
+
if (value !== "true" && value !== "false")
|
|
49
|
+
refuse(`gtd: flagMode must be "true" or "false", got ${JSON.stringify(value)}`)
|
|
50
|
+
return value === "true"
|
|
51
|
+
}
|
|
52
|
+
|
|
38
53
|
/** A shipped flow as a factory: its options override the settings it declares, each in its own kind. */
|
|
39
54
|
export const shipped = (
|
|
40
55
|
flow: Flow,
|
|
@@ -990,6 +990,22 @@ describe("the seam phase's texts", () => {
|
|
|
990
990
|
expect(prompt).toContain("Implement them properly")
|
|
991
991
|
})
|
|
992
992
|
|
|
993
|
+
it("flag mode off asks for the naive version and no release flag, whatever the tier or lap", () => {
|
|
994
|
+
for (const [tier, amend] of [
|
|
995
|
+
["high", false],
|
|
996
|
+
["low", false],
|
|
997
|
+
["high", true],
|
|
998
|
+
] as const) {
|
|
999
|
+
const prompt = renderText(() => implementBuildingPrompt(undefined, tier, amend, false, false))
|
|
1000
|
+
expect(prompt).toContain("Add no release flag — this project ships without release flags")
|
|
1001
|
+
expect(prompt).not.toContain("new release flag")
|
|
1002
|
+
expect(prompt).not.toContain("low risk tier")
|
|
1003
|
+
}
|
|
1004
|
+
expect(
|
|
1005
|
+
renderText(() => implementBuildingPrompt(undefined, "high", false, false, false)),
|
|
1006
|
+
).toContain("the quickest way that works")
|
|
1007
|
+
})
|
|
1008
|
+
|
|
993
1009
|
it("keeps a fix turn to the feedback file's rules", () => {
|
|
994
1010
|
expect(renderText(() => implementFixPrompt())).toContain(".gtd/FEEDBACK.md")
|
|
995
1011
|
})
|