@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.
Files changed (46) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +20 -27
  3. package/dist/chunks/{reserved-B8EC-WE8.mjs → reserved-X2RkNHin.mjs} +34 -116
  4. package/dist/chunks/{review-HdrX0FJ7.mjs → review-v7sh5GF4.mjs} +2 -2
  5. package/dist/chunks/{tail-BSLah2mA.mjs → tail-S04KEewi.mjs} +1 -1
  6. package/dist/workflows/cleanup.mjs +2 -2
  7. package/dist/workflows/feature.mjs +52 -162
  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 +81 -274
  12. package/package.json +1 -1
  13. package/src/workflows/feature/criteria-coverage.feature +0 -1
  14. package/src/workflows/feature/criteria.test.ts +1 -41
  15. package/src/workflows/feature/criteria.ts +2 -14
  16. package/src/workflows/feature/fast-path.feature +0 -1
  17. package/src/workflows/feature/feature.ts +5 -6
  18. package/src/workflows/feature/flag-mode.feature +1 -1
  19. package/src/workflows/feature/lens-models.feature +0 -1
  20. package/src/workflows/feature/lens-review.feature +0 -1
  21. package/src/workflows/feature/naive-test.feature +258 -0
  22. package/src/workflows/feature/one-step-land.feature +0 -1
  23. package/src/workflows/feature/refactor-absorbs.feature +0 -1
  24. package/src/workflows/feature/refactor-first.feature +0 -1
  25. package/src/workflows/feature/refactor-rebuild.feature +0 -1
  26. package/src/workflows/feature/refactor-review.feature +0 -1
  27. package/src/workflows/feature/review-gate.feature +1 -2
  28. package/src/workflows/feature/reviewer-walkthrough.feature +0 -1
  29. package/src/workflows/feature/seam-rejection.feature +0 -1
  30. package/src/workflows/feature/seam.feature +0 -1
  31. package/src/workflows/feature/seam.test.ts +1 -2
  32. package/src/workflows/feature/seam.ts +56 -10
  33. package/src/workflows/feature/standards.feature +0 -1
  34. package/src/workflows/shared/options.ts +9 -1
  35. package/src/workflows/shared/prose.ts +0 -6
  36. package/src/workflows/shared/skills.test.ts +0 -4
  37. package/src/workflows/shared/skills.ts +0 -5
  38. package/src/workflows/shared/steps.ts +1 -1
  39. package/src/workflows/shared/text.test.ts +22 -41
  40. package/src/workflows/shared/text.ts +42 -142
  41. package/src/workflows/shared/vars.ts +2 -3
  42. package/src/workflows/feature/hands-on-skip.feature +0 -316
  43. package/src/workflows/feature/prototype-rounds.feature +0 -156
  44. package/src/workflows/feature/prototype.feature +0 -428
  45. package/src/workflows/feature/prototype.test.ts +0 -43
  46. 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, judged with `flagMode` on: it
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 → a hands-on test of every criterion,
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
- prototypeRounds()
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, prototypeRounds: "0" })
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 hands-on test, the quality lap — and the review
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
- // The hands-on test has its own scenarios.
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, PROTOTYPE, REFACTOR_NOTE, REQUIREMENTS } from "../shared/steps.js"
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, PROTOTYPE]), {
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
- readonly again: ReturnType<typeof budget>
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 vetted(tip, vetting)) ??
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 PROTOTYPE = ".gtd/PROTOTYPE.md"
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 ?? ""