@pmelab/gtd 56.0.0 → 57.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 +20 -27
- package/dist/chunks/{reserved-B8EC-WE8.mjs → reserved-X2RkNHin.mjs} +34 -116
- package/dist/chunks/{review-HdrX0FJ7.mjs → review-v7sh5GF4.mjs} +2 -2
- package/dist/chunks/{tail-BSLah2mA.mjs → tail-S04KEewi.mjs} +1 -1
- package/dist/workflows/cleanup.mjs +2 -2
- package/dist/workflows/feature.mjs +52 -162
- package/dist/workflows/fix.mjs +2 -2
- package/dist/workflows/review.mjs +3 -3
- package/dist/workflows/rollout.mjs +1 -1
- package/dist/workflows.mjs +81 -274
- package/package.json +1 -1
- package/src/workflows/feature/criteria-coverage.feature +0 -1
- package/src/workflows/feature/criteria.test.ts +1 -41
- package/src/workflows/feature/criteria.ts +2 -14
- package/src/workflows/feature/fast-path.feature +0 -1
- package/src/workflows/feature/feature.ts +5 -6
- package/src/workflows/feature/flag-mode.feature +1 -1
- package/src/workflows/feature/lens-models.feature +0 -1
- package/src/workflows/feature/lens-review.feature +0 -1
- package/src/workflows/feature/naive-test.feature +258 -0
- package/src/workflows/feature/one-step-land.feature +0 -1
- package/src/workflows/feature/refactor-absorbs.feature +0 -1
- package/src/workflows/feature/refactor-first.feature +0 -1
- package/src/workflows/feature/refactor-rebuild.feature +0 -1
- package/src/workflows/feature/refactor-review.feature +0 -1
- package/src/workflows/feature/review-gate.feature +1 -2
- package/src/workflows/feature/reviewer-walkthrough.feature +0 -1
- package/src/workflows/feature/seam-rejection.feature +0 -1
- package/src/workflows/feature/seam.feature +0 -1
- package/src/workflows/feature/seam.test.ts +1 -2
- package/src/workflows/feature/seam.ts +56 -10
- package/src/workflows/feature/standards.feature +0 -1
- package/src/workflows/shared/options.ts +9 -1
- package/src/workflows/shared/prose.ts +0 -6
- package/src/workflows/shared/skills.test.ts +0 -4
- package/src/workflows/shared/skills.ts +0 -5
- package/src/workflows/shared/steps.ts +1 -1
- package/src/workflows/shared/text.test.ts +22 -41
- package/src/workflows/shared/text.ts +42 -142
- package/src/workflows/shared/vars.ts +2 -3
- package/src/workflows/feature/hands-on-skip.feature +0 -316
- package/src/workflows/feature/prototype-rounds.feature +0 -156
- package/src/workflows/feature/prototype.feature +0 -428
- package/src/workflows/feature/prototype.test.ts +0 -43
- package/src/workflows/feature/prototype.ts +0 -198
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
start,
|
|
10
10
|
} from "../../flows/index.js"
|
|
11
11
|
import { gate } from "../shared/health.js"
|
|
12
|
-
import { flagModeOn, shipped } from "../shared/options.js"
|
|
12
|
+
import { flagModeOn, naiveTestOn, shipped } from "../shared/options.js"
|
|
13
13
|
import { FEEDBACK, REQUIREMENTS } from "../shared/steps.js"
|
|
14
14
|
import { refusePendingHandOff } from "../shared/tail.js"
|
|
15
15
|
import * as t from "../shared/text.js"
|
|
@@ -23,16 +23,15 @@ import {
|
|
|
23
23
|
} from "./criteria.js"
|
|
24
24
|
import { design } from "./planning.js"
|
|
25
25
|
import { buildTail, isCode, reUnwind, type ReviewOutcome } from "../shared/review.js"
|
|
26
|
-
import { prototypeRounds } from "./prototype.js"
|
|
27
26
|
import { implement, implementing, seamBuild } from "./seam.js"
|
|
28
27
|
import { recordRisk, riskTierOn } from "./tier.js"
|
|
29
28
|
|
|
30
29
|
// The ordinary start. Any change to the tree starts a process: `idle` →
|
|
31
30
|
// `unwind` reverts the sketch (its intent survives in history) → a
|
|
32
|
-
// green-baseline gate → design → a naive pass,
|
|
31
|
+
// green-baseline gate → design → a naive pass, tried by a person with
|
|
32
|
+
// `naiveTest` on and judged with `flagMode` on: it
|
|
33
33
|
// lands as the implementation, or (refactoring first when the judge asks) is
|
|
34
|
-
// built fresh from → the health loop →
|
|
35
|
-
// fixed and re-tested → the triaged quality lap and its finding gate → a
|
|
34
|
+
// built fresh from → the health loop → the triaged quality lap and its finding gate → a
|
|
36
35
|
// reviewer's walkthrough of the whole change for the human, which signs off
|
|
37
36
|
// (the episode ends back at `idle`) or sends a design → implement lap.
|
|
38
37
|
|
|
@@ -141,7 +140,7 @@ export const ordinaryStart = async (): Promise<void> => {
|
|
|
141
140
|
refusePendingHandOff()
|
|
142
141
|
// Read right after idle, so a bad value refuses the landing that would pin it.
|
|
143
142
|
flagModeOn()
|
|
144
|
-
|
|
143
|
+
naiveTestOn()
|
|
145
144
|
const stated = statedCriteria(changes(), head())
|
|
146
145
|
await unwind()
|
|
147
146
|
if (changes(FEEDBACK).some((c) => c.status !== "deleted")) {
|
|
@@ -11,7 +11,7 @@ Feature: flag mode off lands the naive pass with no release flag, seam judge or
|
|
|
11
11
|
"""
|
|
12
12
|
import { feature } from "@pmelab/gtd/workflows/feature"
|
|
13
13
|
export { summary, steering, skills, access } from "@pmelab/gtd/workflows/feature"
|
|
14
|
-
export default feature({ flagMode: false
|
|
14
|
+
export default feature({ flagMode: false })
|
|
15
15
|
"""
|
|
16
16
|
And an environment variable "GTD_QUALITYREVIEWS" set to "correctness"
|
|
17
17
|
And a file "src/calc.ts" with:
|
|
@@ -12,7 +12,6 @@ Feature: each quality lens runs on its own model hint
|
|
|
12
12
|
export { summary, steering, skills, access } from "@pmelab/gtd/workflows/feature"
|
|
13
13
|
export default feature({
|
|
14
14
|
flagMode: false,
|
|
15
|
-
prototypeRounds: "0",
|
|
16
15
|
qualityReviews: "correctness, conventions, test-audit=opus",
|
|
17
16
|
})
|
|
18
17
|
"""
|
|
@@ -11,7 +11,6 @@ Feature: the quality lap's findings are triaged, then decided at the finding gat
|
|
|
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 "correctness"
|
|
16
15
|
And an environment variable "GTD_FLAGMODE" set to "false"
|
|
17
16
|
And a file "src/calc.ts" with:
|
|
@@ -0,0 +1,258 @@
|
|
|
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, or straight to the implementation with `flagMode` off. Notes in
|
|
8
|
+
`.gtd/NAIVE-TEST.md`, a code edit or a requirements edit send it back: the
|
|
9
|
+
pass and the person's code edits leave the tree again, and the next naive
|
|
10
|
+
pass gets the notes and the edits. Every lap ends at the gate again.
|
|
11
|
+
|
|
12
|
+
Rule: with flagMode off
|
|
13
|
+
|
|
14
|
+
Background:
|
|
15
|
+
Given a gtd config with:
|
|
16
|
+
"""
|
|
17
|
+
import { feature } from "@pmelab/gtd/workflows/feature"
|
|
18
|
+
export { summary, steering, skills, access } from "@pmelab/gtd/workflows/feature"
|
|
19
|
+
export default feature({ flagMode: false, naiveTest: true })
|
|
20
|
+
"""
|
|
21
|
+
And an environment variable "GTD_QUALITYREVIEWS" set to ""
|
|
22
|
+
And a file "src/calc.ts" with:
|
|
23
|
+
"""
|
|
24
|
+
export const add = (a: number, b: number) => a + b
|
|
25
|
+
"""
|
|
26
|
+
And the working tree is committed as "feat: add calculator"
|
|
27
|
+
And a file "TODO.md" with:
|
|
28
|
+
"""
|
|
29
|
+
# Add subtract
|
|
30
|
+
|
|
31
|
+
subtract(a, b) returns the difference.
|
|
32
|
+
"""
|
|
33
|
+
And step "unwind" changes nothing
|
|
34
|
+
And step "start-gate.check" changes nothing
|
|
35
|
+
And step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
|
|
36
|
+
"""
|
|
37
|
+
# Requirements
|
|
38
|
+
|
|
39
|
+
## Impact
|
|
40
|
+
|
|
41
|
+
- the calculator module
|
|
42
|
+
|
|
43
|
+
## Acceptance Criteria
|
|
44
|
+
|
|
45
|
+
- AC-1: subtract(a, b) returns a - b.
|
|
46
|
+
"""
|
|
47
|
+
And step "design.gate.answer" changes nothing
|
|
48
|
+
And step "seam.naive" writes "src/calc.test.ts" with:
|
|
49
|
+
"""
|
|
50
|
+
it("[AC-1] subtracts", () => {})
|
|
51
|
+
"""
|
|
52
|
+
And step "seam.naive" 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 "seam.check" changes nothing
|
|
58
|
+
And step "seam.applying" runs its script
|
|
59
|
+
And step "seam.restoring" runs its script
|
|
60
|
+
|
|
61
|
+
Scenario: a green naive pass rests at seam.try, applied to the working tree
|
|
62
|
+
When the process is driven
|
|
63
|
+
Then the process rests at "seam.try"
|
|
64
|
+
And the resting step's content contains "try it by hand"
|
|
65
|
+
And the resting step's content contains "`.gtd/NAIVE-TEST.md`"
|
|
66
|
+
And "src/calc.ts" contains "export const subtract"
|
|
67
|
+
And the commit subjects end with:
|
|
68
|
+
"""
|
|
69
|
+
gtd(agent): seam.naive → seam.check
|
|
70
|
+
gtd(check): seam.check → seam.applying
|
|
71
|
+
gtd(check): seam.applying → seam.try
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
Scenario: a clean landing signs the pass off, takes it out and lands it as the implementation
|
|
75
|
+
When the process is driven
|
|
76
|
+
Then the process rests at "seam.try"
|
|
77
|
+
When gtd lands
|
|
78
|
+
And step "implement.applying" runs its script
|
|
79
|
+
And step "implement.health.check" changes nothing
|
|
80
|
+
And step "implement.closing" runs its script
|
|
81
|
+
And the process is driven
|
|
82
|
+
Then the process rests at "build.review.reviewing"
|
|
83
|
+
And "src/calc.ts" contains "export const subtract"
|
|
84
|
+
And the commit subjects end with:
|
|
85
|
+
"""
|
|
86
|
+
gtd(check): seam.applying → seam.try
|
|
87
|
+
gtd(human): seam.try → seam.restoring
|
|
88
|
+
gtd(check): seam.restoring → implement.applying
|
|
89
|
+
gtd(check): implement.applying → implement.health.check
|
|
90
|
+
gtd(check): implement.health.check → implement.closing
|
|
91
|
+
gtd(check): implement.closing → build.review.reviewing
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
Scenario: notes and a code edit send the pass back, out of the tree, to a naive pass that reads both
|
|
95
|
+
Given step "seam.naive", when prompted with "> subtract(5, 3) printed 8, not 2.", writes "notes-read.txt" with:
|
|
96
|
+
"""
|
|
97
|
+
read
|
|
98
|
+
"""
|
|
99
|
+
And step "seam.naive", when prompted with "-- . ':(exclude).gtd'", writes "edits-read.txt" with:
|
|
100
|
+
"""
|
|
101
|
+
read
|
|
102
|
+
"""
|
|
103
|
+
When the process is driven
|
|
104
|
+
Then the process rests at "seam.try"
|
|
105
|
+
Given a file ".gtd/NAIVE-TEST.md" with:
|
|
106
|
+
"""
|
|
107
|
+
subtract(5, 3) printed 8, not 2.
|
|
108
|
+
"""
|
|
109
|
+
And a file "src/calc.ts" with:
|
|
110
|
+
"""
|
|
111
|
+
export const add = (a: number, b: number) => a + b
|
|
112
|
+
export const subtract = (a: number, b: number) => a - b
|
|
113
|
+
"""
|
|
114
|
+
And a file "src/hint.ts" with:
|
|
115
|
+
"""
|
|
116
|
+
export const hint = "subtract, not add"
|
|
117
|
+
"""
|
|
118
|
+
When gtd lands
|
|
119
|
+
And the process is driven
|
|
120
|
+
Then the process rests at "seam.try"
|
|
121
|
+
And "src/hint.ts" does not exist
|
|
122
|
+
And "notes-read.txt" contains "read"
|
|
123
|
+
And "edits-read.txt" contains "read"
|
|
124
|
+
And ".gtd/NAIVE-TEST.md" does not exist
|
|
125
|
+
And the commit subjects end with:
|
|
126
|
+
"""
|
|
127
|
+
gtd(check): seam.applying → seam.try
|
|
128
|
+
gtd(human): seam.try → seam.restoring
|
|
129
|
+
gtd(check): seam.restoring → seam.naive
|
|
130
|
+
gtd(agent): seam.naive → seam.check
|
|
131
|
+
gtd(check): seam.check → seam.applying
|
|
132
|
+
gtd(check): seam.applying → seam.try
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
Scenario: notes alone send the pass back with no edits to read
|
|
136
|
+
Given step "seam.naive", when prompted with "They edited the code", writes "edits-read.txt" with:
|
|
137
|
+
"""
|
|
138
|
+
read
|
|
139
|
+
"""
|
|
140
|
+
When the process is driven
|
|
141
|
+
Then the process rests at "seam.try"
|
|
142
|
+
Given a file ".gtd/NAIVE-TEST.md" with:
|
|
143
|
+
"""
|
|
144
|
+
subtract adds.
|
|
145
|
+
"""
|
|
146
|
+
When gtd lands
|
|
147
|
+
And the process is driven
|
|
148
|
+
Then the process rests at "seam.try"
|
|
149
|
+
And "edits-read.txt" does not exist
|
|
150
|
+
|
|
151
|
+
Scenario: a requirements edit at seam.try stays, and sends the pass back
|
|
152
|
+
When the process is driven
|
|
153
|
+
Then the process rests at "seam.try"
|
|
154
|
+
Given a file ".gtd/REQUIREMENTS.md" with:
|
|
155
|
+
"""
|
|
156
|
+
# Requirements
|
|
157
|
+
|
|
158
|
+
## Impact
|
|
159
|
+
|
|
160
|
+
- the calculator module
|
|
161
|
+
|
|
162
|
+
## Acceptance Criteria
|
|
163
|
+
|
|
164
|
+
- AC-1: subtract(a, b) returns a - b.
|
|
165
|
+
- AC-2: subtract(a, b) rejects NaN.
|
|
166
|
+
"""
|
|
167
|
+
When gtd lands
|
|
168
|
+
And the process is driven
|
|
169
|
+
Then the process rests at "seam.try"
|
|
170
|
+
And ".gtd/REQUIREMENTS.md" contains "AC-2: subtract(a, b) rejects NaN."
|
|
171
|
+
And the commit subjects end with:
|
|
172
|
+
"""
|
|
173
|
+
gtd(human): seam.try → seam.restoring
|
|
174
|
+
gtd(check): seam.restoring → seam.naive
|
|
175
|
+
gtd(agent): seam.naive → seam.check
|
|
176
|
+
gtd(check): seam.check → seam.applying
|
|
177
|
+
gtd(check): seam.applying → seam.try
|
|
178
|
+
"""
|
|
179
|
+
|
|
180
|
+
Rule: with flagMode on
|
|
181
|
+
|
|
182
|
+
Background:
|
|
183
|
+
Given a gtd config with:
|
|
184
|
+
"""
|
|
185
|
+
import { feature } from "@pmelab/gtd/workflows/feature"
|
|
186
|
+
export { summary, steering, skills, access } from "@pmelab/gtd/workflows/feature"
|
|
187
|
+
export default feature({ naiveTest: true })
|
|
188
|
+
"""
|
|
189
|
+
And an environment variable "GTD_QUALITYREVIEWS" set to ""
|
|
190
|
+
And a file "src/calc.ts" with:
|
|
191
|
+
"""
|
|
192
|
+
export const add = (a: number, b: number) => a + b
|
|
193
|
+
"""
|
|
194
|
+
And the working tree is committed as "feat: add calculator"
|
|
195
|
+
And a file "TODO.md" with:
|
|
196
|
+
"""
|
|
197
|
+
# Add subtract
|
|
198
|
+
|
|
199
|
+
subtract(a, b) returns the difference.
|
|
200
|
+
"""
|
|
201
|
+
And step "unwind" changes nothing
|
|
202
|
+
And step "start-gate.check" changes nothing
|
|
203
|
+
And step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
|
|
204
|
+
"""
|
|
205
|
+
# Requirements
|
|
206
|
+
|
|
207
|
+
## Impact
|
|
208
|
+
|
|
209
|
+
- the calculator module
|
|
210
|
+
|
|
211
|
+
## Acceptance Criteria
|
|
212
|
+
|
|
213
|
+
- AC-1: subtract(a, b) returns a - b.
|
|
214
|
+
"""
|
|
215
|
+
And step "design.gate.answer" changes nothing
|
|
216
|
+
And step "seam.naive" writes "src/calc.test.ts" with:
|
|
217
|
+
"""
|
|
218
|
+
it("[AC-1] subtracts", () => {})
|
|
219
|
+
"""
|
|
220
|
+
And step "seam.naive" writes "src/calc.ts" with:
|
|
221
|
+
"""
|
|
222
|
+
export const add = (a: number, b: number) => a + b
|
|
223
|
+
export const subtract = (a: number, b: number) => a + b
|
|
224
|
+
"""
|
|
225
|
+
And step "seam.check" changes nothing
|
|
226
|
+
And step "seam.applying" runs its script
|
|
227
|
+
And step "seam.restoring" runs its script
|
|
228
|
+
|
|
229
|
+
Scenario: with flagMode on the person tries the pass before the seam judge rules
|
|
230
|
+
When the process is driven
|
|
231
|
+
Then the process rests at "seam.try"
|
|
232
|
+
And the resting step's content contains "the seam judge rules on its shape"
|
|
233
|
+
When gtd lands
|
|
234
|
+
And the process is driven
|
|
235
|
+
Then the process rests at "seam.judge"
|
|
236
|
+
|
|
237
|
+
Rule: with a naiveTest that is neither true nor false
|
|
238
|
+
|
|
239
|
+
Background:
|
|
240
|
+
Given an environment variable "GTD_NAIVETEST" set to "maybe"
|
|
241
|
+
And a gtd config with:
|
|
242
|
+
"""
|
|
243
|
+
import { feature } from "@pmelab/gtd/workflows/feature"
|
|
244
|
+
export { summary, steering, skills, access } from "@pmelab/gtd/workflows/feature"
|
|
245
|
+
export default feature()
|
|
246
|
+
"""
|
|
247
|
+
And a file "src/calc.ts" with:
|
|
248
|
+
"""
|
|
249
|
+
export const add = (a: number, b: number) => a + b
|
|
250
|
+
"""
|
|
251
|
+
And the working tree is committed as "feat: add calculator"
|
|
252
|
+
And a file "TODO.md" with:
|
|
253
|
+
"""
|
|
254
|
+
# Add subtract
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
Scenario: the landing that would pin it is refused
|
|
258
|
+
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:
|
|
@@ -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"
|
|
@@ -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"
|
|
@@ -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"
|
|
@@ -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
|
|
|
@@ -4,13 +4,12 @@ Feature: a feature process ends at the human review
|
|
|
4
4
|
After the quality lap the process rests at the review gate,
|
|
5
5
|
`.gtd/REVIEW.md`. A sign-off ends the process. A note asking for a change in
|
|
6
6
|
behaviour starts a feedback lap — design, then implement with no new naive
|
|
7
|
-
pass or seam judge, the
|
|
7
|
+
pass or seam judge, the quality lap — and the review
|
|
8
8
|
again. Its design keeps a built criterion's ID and numbers
|
|
9
9
|
new behaviour above every ID handed out.
|
|
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 ""
|
|
15
14
|
And an environment variable "GTD_FLAGMODE" set to "false"
|
|
16
15
|
And a file "src/calc.ts" with:
|
|
@@ -10,7 +10,6 @@ Feature: a reviewer walks the human through the feature's code
|
|
|
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 ""
|
|
15
14
|
And an environment variable "GTD_FLAGMODE" set to "false"
|
|
16
15
|
And a file "src/calc.ts" with:
|
|
@@ -9,7 +9,6 @@ Feature: rejected naive passes walk one fixed path through the steer gate to the
|
|
|
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
|
And a file "src/calc.ts" with:
|
|
@@ -7,7 +7,6 @@ Feature: the naive pass and seam judge decide how a feature is built
|
|
|
7
7
|
|
|
8
8
|
Background:
|
|
9
9
|
Given the shipped workflows, as gtd install scaffolds them
|
|
10
|
-
And an environment variable "GTD_PROTOTYPEROUNDS" set to "0"
|
|
11
10
|
And the gtd config ends with:
|
|
12
11
|
"""
|
|
13
12
|
export const config = {
|
|
@@ -403,8 +403,7 @@ describe("implement", () => {
|
|
|
403
403
|
lastOptions = undefined
|
|
404
404
|
installContext(
|
|
405
405
|
fixtureContext(
|
|
406
|
-
|
|
407
|
-
{ vars: { prototypeRounds: "0" } },
|
|
406
|
+
{},
|
|
408
407
|
{
|
|
409
408
|
step: (request: StepRequest) => {
|
|
410
409
|
requests.push(request)
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
agent,
|
|
4
4
|
applyScript,
|
|
5
5
|
changes,
|
|
6
|
+
changesSince,
|
|
6
7
|
check,
|
|
7
8
|
codeChanges,
|
|
8
9
|
env,
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
read,
|
|
15
16
|
refuse,
|
|
16
17
|
removeScript,
|
|
18
|
+
restoreScript,
|
|
17
19
|
run,
|
|
18
20
|
scope,
|
|
19
21
|
vars,
|
|
@@ -22,11 +24,10 @@ import {
|
|
|
22
24
|
type DiffShapeResult,
|
|
23
25
|
type KeptTip,
|
|
24
26
|
} from "../../flows/index.js"
|
|
25
|
-
import { coder, FEEDBACK,
|
|
27
|
+
import { coder, FEEDBACK, NAIVE_TEST, REFACTOR_NOTE, REQUIREMENTS } from "../shared/steps.js"
|
|
26
28
|
import * as t from "../shared/text.js"
|
|
27
29
|
import { defaults } from "../shared/vars.js"
|
|
28
30
|
import { green } from "./green.js"
|
|
29
|
-
import { prototypeTest } from "./prototype.js"
|
|
30
31
|
import { criterionIds, requireCriteria, requireCriteriaFrozen } from "./criteria.js"
|
|
31
32
|
import {
|
|
32
33
|
COMMENT,
|
|
@@ -36,7 +37,7 @@ import {
|
|
|
36
37
|
reviewedRefactor,
|
|
37
38
|
} from "./refactor.js"
|
|
38
39
|
import { isCode } from "../shared/review.js"
|
|
39
|
-
import { flagModeOn } from "../shared/options.js"
|
|
40
|
+
import { flagModeOn, naiveTestOn } from "../shared/options.js"
|
|
40
41
|
import type { RiskTier } from "./tier.js"
|
|
41
42
|
|
|
42
43
|
/** Naive-pass retries after a `reject` or a red suite; the next one rests at `seam.steer`. */
|
|
@@ -53,7 +54,7 @@ export const judgeSeam = (tip: KeptTip): Promise<DiffShapeResult> =>
|
|
|
53
54
|
exempt: tip.changes.filter((c) => c.status === "added").map((c) => c.path),
|
|
54
55
|
})
|
|
55
56
|
|
|
56
|
-
export const naivePass = (retry?: t.NaiveRetry): Promise<void> =>
|
|
57
|
+
export const naivePass = (retry?: t.NaiveRetry | t.NaiveTested): Promise<void> =>
|
|
57
58
|
t.agentWithSkills("naive", t.naivePassPrompt(retry), {
|
|
58
59
|
label: retry === undefined ? "Writing the naive pass" : "Rewriting the naive pass",
|
|
59
60
|
keep: true,
|
|
@@ -226,9 +227,8 @@ export const implementing = (options: ImplementOptions): Promise<readonly string
|
|
|
226
227
|
if (built) await build(options)
|
|
227
228
|
else requireCriteriaFrozen(REQUIREMENTS)
|
|
228
229
|
await green()
|
|
229
|
-
await prototypeTest()
|
|
230
230
|
const ids = criterionIds(read(REQUIREMENTS) ?? "")
|
|
231
|
-
await run("closing", removeScript([REQUIREMENTS, REFACTOR_NOTE
|
|
231
|
+
await run("closing", removeScript([REQUIREMENTS, REFACTOR_NOTE]), {
|
|
232
232
|
label: "Closing out the implementation",
|
|
233
233
|
})
|
|
234
234
|
return ids
|
|
@@ -277,7 +277,7 @@ const budget = (): ((next: t.NaiveRetry) => Promise<Verdict>) => {
|
|
|
277
277
|
}
|
|
278
278
|
|
|
279
279
|
interface Vetting {
|
|
280
|
-
|
|
280
|
+
again: ReturnType<typeof budget>
|
|
281
281
|
/** Set once a human overrules a test fault: the rule does not fit this change, so later passes skip it. */
|
|
282
282
|
waived: boolean
|
|
283
283
|
}
|
|
@@ -304,16 +304,62 @@ const ruled = async (tip: KeptTip, again: Vetting["again"]): Promise<Decision |
|
|
|
304
304
|
return next.kind === "overruled" ? { reference: tip.hash, tip } : next
|
|
305
305
|
}
|
|
306
306
|
|
|
307
|
+
/** Back to `before`: every code path, and the notes file. `.gtd/` edits (the requirements) stay. */
|
|
308
|
+
const untryScript = (before: string): string => {
|
|
309
|
+
const code = changesSince(before).filter((c) => isCode(c.path))
|
|
310
|
+
return restoreScript(
|
|
311
|
+
head(),
|
|
312
|
+
{
|
|
313
|
+
restore: code.filter((c) => c.status !== "added").map((c) => c.path),
|
|
314
|
+
remove: [...code.filter((c) => c.status === "added").map((c) => c.path), NAIVE_TEST],
|
|
315
|
+
},
|
|
316
|
+
before,
|
|
317
|
+
)
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* A person tries the green pass `tip` in the working tree. Resolves
|
|
322
|
+
* `undefined` on a clean landing (signed off), else what they sent back;
|
|
323
|
+
* either way the pass, their code edits and the notes file leave the tree.
|
|
324
|
+
*/
|
|
325
|
+
const tried = async (tip: KeptTip): Promise<t.NaiveTested | undefined> => {
|
|
326
|
+
const before = head()
|
|
327
|
+
await run("applying", applyScript(tip.hash, FEEDBACK, t.naiveApplyFailure(tip.hash), [".gtd"]), {
|
|
328
|
+
label: "Applying the naive pass to try it",
|
|
329
|
+
})
|
|
330
|
+
await human("try", {
|
|
331
|
+
message: t.naiveTryMessage(flagModeOn()),
|
|
332
|
+
label: "Try the naive pass",
|
|
333
|
+
file: NAIVE_TEST,
|
|
334
|
+
acceptClean: true,
|
|
335
|
+
})
|
|
336
|
+
const landed = changes()
|
|
337
|
+
const edits = landed.some((c) => isCode(c.path)) ? head() : undefined
|
|
338
|
+
const notes = read(NAIVE_TEST)?.trim() || undefined
|
|
339
|
+
if (landed.some((c) => c.path === REQUIREMENTS)) requireCriteria(REQUIREMENTS)
|
|
340
|
+
await run("restoring", untryScript(before), { label: "Taking the naive pass out again" })
|
|
341
|
+
return landed.length === 0 ? undefined : { tested: tip.hash, notes, edits }
|
|
342
|
+
}
|
|
343
|
+
|
|
307
344
|
const decide = (): Promise<Decision> =>
|
|
308
345
|
scope("seam", async () => {
|
|
309
346
|
const vetting: Vetting = { again: budget(), waived: false }
|
|
310
|
-
let retry: t.NaiveRetry | undefined
|
|
347
|
+
let retry: t.NaiveRetry | t.NaiveTested | undefined
|
|
311
348
|
for (;;) {
|
|
312
349
|
await naivePass(retry)
|
|
313
350
|
const tip = kept("naive")!
|
|
351
|
+
const verdict = await vetted(tip, vetting)
|
|
352
|
+
if (verdict === undefined && naiveTestOn()) {
|
|
353
|
+
const sentBack = await tried(tip)
|
|
354
|
+
if (sentBack !== undefined) {
|
|
355
|
+
// A person's feedback is no failed attempt: the next pass gets a full retry budget.
|
|
356
|
+
vetting.again = budget()
|
|
357
|
+
retry = sentBack
|
|
358
|
+
continue
|
|
359
|
+
}
|
|
360
|
+
}
|
|
314
361
|
const outcome =
|
|
315
|
-
(await
|
|
316
|
-
(flagModeOn() ? await ruled(tip, vetting.again) : { reference: tip.hash, tip })
|
|
362
|
+
verdict ?? (flagModeOn() ? await ruled(tip, vetting.again) : { reference: tip.hash, tip })
|
|
317
363
|
if (!("kind" in outcome)) return outcome
|
|
318
364
|
retry = outcome.kind === "retry" ? outcome.retry : undefined
|
|
319
365
|
}
|
|
@@ -11,7 +11,6 @@ Feature: the review learns standards from the human's answers
|
|
|
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_FLAGMODE" set to "false"
|
|
17
16
|
And a file "src/calc.ts" with:
|
|
@@ -24,11 +24,11 @@ export const ShippedOptions = Schema.Struct({
|
|
|
24
24
|
seamAllow: setting,
|
|
25
25
|
qualityReviews: setting,
|
|
26
26
|
refactorQualityReviews: setting,
|
|
27
|
-
prototypeRounds: setting,
|
|
28
27
|
testCommand: setting,
|
|
29
28
|
plannerModel: setting,
|
|
30
29
|
coderModel: setting,
|
|
31
30
|
flagMode: Schema.optionalWith(Schema.Boolean, { exact: true }),
|
|
31
|
+
naiveTest: Schema.optionalWith(Schema.Boolean, { exact: true }),
|
|
32
32
|
})
|
|
33
33
|
|
|
34
34
|
export type ShippedOptions = Schema.Schema.Encoded<typeof ShippedOptions>
|
|
@@ -53,6 +53,14 @@ export const flagModeOn = (): boolean => {
|
|
|
53
53
|
return value === "true"
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/** The `naiveTest` setting, pinned at process start. Anything but true/false fails rather than guess. */
|
|
57
|
+
export const naiveTestOn = (): boolean => {
|
|
58
|
+
const value = vars.naiveTest ?? defaults.naiveTest!
|
|
59
|
+
if (value !== "true" && value !== "false")
|
|
60
|
+
refuse(`gtd: naiveTest must be "true" or "false", got ${JSON.stringify(value)}`)
|
|
61
|
+
return value === "true"
|
|
62
|
+
}
|
|
63
|
+
|
|
56
64
|
/** A shipped flow as a factory: its options override the settings it declares, each in its own kind. */
|
|
57
65
|
export const shipped = (
|
|
58
66
|
flow: Flow,
|
|
@@ -88,12 +88,6 @@ things when redirected — a failing check, or reviewer feedback. Stay
|
|
|
88
88
|
strictly inside that task; never touch code outside it. Treat feedback as the
|
|
89
89
|
diagnosis to act on; discard it, with reason, only when simply wrong.`
|
|
90
90
|
|
|
91
|
-
export const testerPersona = `You are the hands-on tester in gtd's build pipeline: use what was just
|
|
92
|
-
built the way a person would — run the real program, open the real
|
|
93
|
-
page, call the real endpoint — and report exactly what you did and
|
|
94
|
-
what you saw. Never fix anything yourself, and never pass a criterion
|
|
95
|
-
you did not watch hold.`
|
|
96
|
-
|
|
97
91
|
export const finisherPersona = `You are the closing identity in gtd's build pipeline — the last coder
|
|
98
92
|
before it closes. Fix a late-breaking failing check after sign-off,
|
|
99
93
|
focused and minimal. Every turn lands its own commit — nothing here
|
|
@@ -29,10 +29,6 @@ describe("the bundled workflow's skills export", () => {
|
|
|
29
29
|
"implement",
|
|
30
30
|
"implement.fix.suite",
|
|
31
31
|
"implement.health",
|
|
32
|
-
"implement.prototype",
|
|
33
|
-
"implement.prototype.fix",
|
|
34
|
-
"implement.prototype.fix.suite",
|
|
35
|
-
"implement.prototype.health",
|
|
36
32
|
"build.quality.correctness",
|
|
37
33
|
"build.quality.owasp-security",
|
|
38
34
|
"build.quality.ponytail-review",
|
|
@@ -33,11 +33,6 @@ export const skills = (
|
|
|
33
33
|
seam: ["incremental-implementation"],
|
|
34
34
|
implement: ["test-driven-development", "incremental-implementation"],
|
|
35
35
|
"implement.fix.suite": ["debugging-and-error-recovery"],
|
|
36
|
-
// The hands-on tester runs the program, never the suite: no TDD.
|
|
37
|
-
"implement.prototype": [],
|
|
38
|
-
"implement.prototype.fix": ["test-driven-development", "incremental-implementation"],
|
|
39
|
-
"implement.prototype.fix.suite": ["debugging-and-error-recovery"],
|
|
40
|
-
"implement.prototype.health": ["debugging-and-error-recovery"],
|
|
41
36
|
// `health` is shared code reached from both `implement` and `build`.
|
|
42
37
|
"implement.health": ["debugging-and-error-recovery"],
|
|
43
38
|
...lensScopes(
|
|
@@ -14,7 +14,7 @@ export const REVIEW = ".gtd/REVIEW.md"
|
|
|
14
14
|
export const REFACTOR = ".gtd/REFACTOR.md"
|
|
15
15
|
export const REFACTOR_NOTE = ".gtd/REFACTOR-NOTE.md"
|
|
16
16
|
export const QUALITY = ".gtd/QUALITY.md"
|
|
17
|
-
export const
|
|
17
|
+
export const NAIVE_TEST = ".gtd/NAIVE-TEST.md"
|
|
18
18
|
|
|
19
19
|
export const planner = (): string => env.plannerModel ?? ""
|
|
20
20
|
export const coder = (): string => env.coderModel ?? ""
|