@pmelab/gtd 51.0.1 → 52.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 (62) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +41 -38
  3. package/dist/chunks/{reserved-CUkk9XgL.mjs → reserved-D0MKVFFa.mjs} +28 -34
  4. package/dist/chunks/{review-BaCXlIT2.mjs → review-ZzUQH1KZ.mjs} +11 -9
  5. package/dist/chunks/{steering-DtUVUz9l.mjs → steering-CLhu8C7q.mjs} +262 -52
  6. package/dist/chunks/{tail-CX6Pdsql.mjs → tail-I1-vVq0P.mjs} +1 -1
  7. package/dist/gtd.bundle.mjs +198 -43
  8. package/dist/steering.mjs +2 -2
  9. package/dist/testkit.mjs +1 -1
  10. package/dist/web/main.css +1 -1
  11. package/dist/web/main.js +510 -147
  12. package/dist/workflow-kit.mjs +1 -1
  13. package/dist/workflows/cleanup.mjs +2 -2
  14. package/dist/workflows/feature.mjs +181 -222
  15. package/dist/workflows/fix.mjs +3 -3
  16. package/dist/workflows/review.mjs +3 -3
  17. package/dist/workflows/rollout.mjs +1 -1
  18. package/dist/workflows.mjs +478 -313
  19. package/package.json +1 -1
  20. package/src/steering/FORMATS.md +4 -1
  21. package/src/steering/SteeringFormat.ts +7 -1
  22. package/src/steering/contract.test.ts +2 -1
  23. package/src/steering/fixtures/review/sectioned.md +31 -0
  24. package/src/steering/fixtures/review/sectioned.read.json +119 -0
  25. package/src/steering/index.ts +4 -0
  26. package/src/steering/qa.ts +1 -1
  27. package/src/steering/review.test.ts +270 -4
  28. package/src/steering/review.ts +328 -69
  29. package/src/workflows/feature/criteria.test.ts +39 -1
  30. package/src/workflows/feature/criteria.ts +21 -7
  31. package/src/workflows/feature/fast-path.feature +1 -6
  32. package/src/workflows/feature/feature.ts +1 -2
  33. package/src/workflows/feature/flag-mode.feature +1 -6
  34. package/src/workflows/feature/green.ts +22 -0
  35. package/src/workflows/feature/hands-on-skip.feature +344 -0
  36. package/src/workflows/feature/lens-models.feature +0 -4
  37. package/src/workflows/feature/lens-review.feature +6 -8
  38. package/src/workflows/feature/one-step-land.feature +1 -6
  39. package/src/workflows/feature/prototype-rounds.feature +1 -1
  40. package/src/workflows/feature/prototype.feature +10 -9
  41. package/src/workflows/feature/prototype.ts +48 -17
  42. package/src/workflows/feature/refactor-absorbs.feature +3 -8
  43. package/src/workflows/feature/refactor-first.feature +3 -8
  44. package/src/workflows/feature/refactor-rebuild.feature +7 -12
  45. package/src/workflows/feature/refactor-review.feature +52 -72
  46. package/src/workflows/feature/review-answers.feature +90 -5
  47. package/src/workflows/feature/review-gate.feature +11 -53
  48. package/src/workflows/feature/reviewer-walkthrough.feature +29 -12
  49. package/src/workflows/feature/seam-rejection.feature +1 -6
  50. package/src/workflows/feature/seam.feature +1 -6
  51. package/src/workflows/feature/seam.test.ts +1 -1
  52. package/src/workflows/feature/seam.ts +2 -3
  53. package/src/workflows/feature/severity-budget.feature +7 -7
  54. package/src/workflows/feature/severity-sorted-review.feature +50 -54
  55. package/src/workflows/feature/slice-findings.feature +5 -15
  56. package/src/workflows/feature/slicing.feature +4 -24
  57. package/src/workflows/feature/standards.feature +0 -4
  58. package/src/workflows/shared/review.ts +26 -6
  59. package/src/workflows/shared/text.test.ts +45 -11
  60. package/src/workflows/shared/text.ts +45 -38
  61. package/src/workflows/feature/coverage.feature +0 -165
  62. package/src/workflows/feature/coverage.ts +0 -120
@@ -15,6 +15,8 @@ import * as t from "../shared/text.js"
15
15
  export interface Criterion {
16
16
  readonly id: string
17
17
  readonly text: string
18
+ /** Tagged `(no hands-on)`: its tests prove it, so the hands-on test skips it. */
19
+ readonly noHandsOn?: true
18
20
  }
19
21
 
20
22
  /** Acceptance criteria the human's sketch stated outright, ready to normalise. */
@@ -29,7 +31,13 @@ export interface StatedCriteria {
29
31
  /** Below this the judge's `yes` is not trusted: a wrong skip builds against criteria nobody can check. */
30
32
  const CLEAR_MIN_P = 0.8
31
33
 
32
- const ID = /^(AC-\d+):\s*(.*)$/
34
+ const ID = /^(AC-\d+)(\s*\(no hands-on\))?:\s*(.*)$/
35
+
36
+ const criterion = (id: RegExpExecArray, as = id[1]!): Criterion => ({
37
+ id: as,
38
+ text: id[3]!,
39
+ ...(id[2] === undefined ? {} : { noHandsOn: true }),
40
+ })
33
41
 
34
42
  /** The list items under the first heading `title` matches (at `level` when given), up to the next heading; wrapped lines joined, fenced lines ignored. */
35
43
  const listUnder = (text: string, title: RegExp, level?: number): string[] | undefined => {
@@ -66,7 +74,7 @@ const listUnder = (text: string, title: RegExp, level?: number): string[] | unde
66
74
  export const criteriaOf = (text: string): readonly Criterion[] | undefined =>
67
75
  listUnder(text, /^acceptance criteria$/i, 2)?.map((item) => {
68
76
  const id = ID.exec(item)
69
- return id === null ? { id: "", text: item } : { id: id[1]!, text: id[2]! }
77
+ return id === null ? { id: "", text: item } : criterion(id)
70
78
  })
71
79
 
72
80
  /**
@@ -90,6 +98,12 @@ export const criterionIds = (text: string, slice?: CriteriaSlice): string[] =>
90
98
  !(slice?.except ?? []).includes(id),
91
99
  )
92
100
 
101
+ /** The ID'd criteria of `text` (`slice`'s when given) a person can try by hand: none tagged `(no hands-on)`. */
102
+ export const handsOnIds = (text: string, slice?: CriteriaSlice): string[] => {
103
+ const tagged = (criteriaOf(text) ?? []).filter((c) => c.noHandsOn).map((c) => c.id)
104
+ return criterionIds(text, slice).filter((id) => !tagged.includes(id))
105
+ }
106
+
93
107
  /** `slice`'s IDs in `.gtd/REQUIREMENTS.md` as it is now; `undefined` for an unsliced change. */
94
108
  export const sliceIds = (slice: CriteriaSlice | undefined): string[] | undefined =>
95
109
  slice === undefined ? undefined : criterionIds(read(REQUIREMENTS) ?? "", slice)
@@ -98,11 +112,11 @@ export const sliceIds = (slice: CriteriaSlice | undefined): string[] | undefined
98
112
  const numbered = (items: readonly string[]): Criterion[] => {
99
113
  const ids = items.map((item) => ID.exec(item))
100
114
  const own = ids.every((id) => id !== null) && new Set(ids.map((id) => id![1])).size === ids.length
101
- return items.map((item, i) =>
102
- own
103
- ? { id: ids[i]![1]!, text: ids[i]![2]! }
104
- : { id: `AC-${i + 1}`, text: item.replace(ID, "$2") },
105
- )
115
+ return items.map((item, i) => {
116
+ const id = ids[i]
117
+ if (own) return criterion(id!)
118
+ return id === null ? { id: `AC-${i + 1}`, text: item } : criterion(id!, `AC-${i + 1}`)
119
+ })
106
120
  }
107
121
 
108
122
  const STATED = /^acceptance criteria:?$/i
@@ -27,10 +27,6 @@ Feature: a trivial change takes the same few beats at either risk tier
27
27
  And step "design.gate.answer" changes nothing
28
28
  And step "implement.health.check" changes nothing
29
29
  And step "implement.closing" runs its script
30
- And judge step "implement.coverage" answers:
31
- """
32
- [{"id":"AC-1","answer":"yes","p":0.9}]
33
- """
34
30
  And step "build.quality.correctness.reviewing" changes nothing
35
31
 
36
32
  Scenario Outline: a one-line fix runs from idle to the review gate with the same beats at either tier
@@ -78,8 +74,7 @@ Feature: a trivial change takes the same few beats at either risk tier
78
74
  gtd(check): seam.check → seam.judge
79
75
  gtd(judge): seam.judge → implement.applying
80
76
  gtd(check): implement.applying → implement.health.check
81
- gtd(check): implement.health.check → implement.coverage
82
- gtd(judge): implement.coverage → implement.closing
77
+ gtd(check): implement.health.check → implement.closing
83
78
  gtd(check): implement.closing → build.quality.correctness.reviewing
84
79
  gtd(agent): build.quality.correctness.reviewing → build.review.reviewing
85
80
  """
@@ -123,7 +123,6 @@ const buildSlice = async (sliceBase: string, build: SliceBuild): Promise<void> =
123
123
  naive: seam.land === true ? seam.reference : undefined,
124
124
  rebuild: seam.rebuild,
125
125
  slice: build.criteria,
126
- base: build.criteria === undefined ? undefined : sliceBase,
127
126
  more: build.more,
128
127
  })
129
128
  // Closing kept the criteria exactly when there is more to build, so this reads as it did.
@@ -179,7 +178,7 @@ const reviewedTail = (
179
178
  )
180
179
 
181
180
  // seam.naive / seam.judge never run on a feedback lap: its design → implement is built unjudged
182
- // and unrefactored, held to every criterion's coverage since the process start.
181
+ // and unrefactored.
183
182
  const featureFeedback = async (
184
183
  first: ReviewOutcome,
185
184
  lensBase: string,
@@ -61,10 +61,6 @@ Feature: flag mode off lands the naive pass with no release flag, seam judge or
61
61
  And step "implement.applying" runs its script
62
62
  And step "implement.health.check" changes nothing
63
63
  And step "implement.closing" runs its script
64
- And judge step "implement.coverage" answers:
65
- """
66
- [{"id":"AC-1","answer":"yes","p":0.9}]
67
- """
68
64
  And step "build.quality.correctness.reviewing" changes nothing
69
65
  When the process is driven
70
66
  Then the process rests at "build.review.reviewing"
@@ -82,8 +78,7 @@ Feature: flag mode off lands the naive pass with no release flag, seam judge or
82
78
  gtd(agent): seam.naive → seam.check
83
79
  gtd(check): seam.check → implement.applying
84
80
  gtd(check): implement.applying → implement.health.check
85
- gtd(check): implement.health.check → implement.coverage
86
- gtd(judge): implement.coverage → implement.closing
81
+ gtd(check): implement.health.check → implement.closing
87
82
  gtd(check): implement.closing → build.quality.correctness.reviewing
88
83
  gtd(agent): build.quality.correctness.reviewing → build.review.reviewing
89
84
  """
@@ -0,0 +1,22 @@
1
+ import { healthy } from "../shared/health.js"
2
+ import { coder, FEEDBACK, REQUIREMENTS } from "../shared/steps.js"
3
+ import * as t from "../shared/text.js"
4
+ import { requireCriteriaFrozen } from "./criteria.js"
5
+
6
+ export const green = (guard?: () => void): Promise<void> =>
7
+ healthy(
8
+ () =>
9
+ t.agentWithSkills("fix.suite.fixing", t.implementFixPrompt(), {
10
+ label: "Fixing the check",
11
+ file: FEEDBACK,
12
+ model: coder(),
13
+ system: t.builderSystem(),
14
+ }),
15
+ {
16
+ guard: () => {
17
+ requireCriteriaFrozen(REQUIREMENTS)
18
+ guard?.()
19
+ },
20
+ guardRests: false,
21
+ },
22
+ )
@@ -0,0 +1,344 @@
1
+ @inmem
2
+ Feature: the hands-on test tries only the criteria a person can observe
3
+
4
+ Design may tag a criterion no person can try by using the change — prompt
5
+ wording, internal wiring — by writing `(no hands-on)` between its ID and the
6
+ colon. At every hands-on test, implement.prototype.observable asks a judge,
7
+ per untagged criterion, whether a person can observe it by using the
8
+ software; a tagged one is never asked about. Every ID it does not answer
9
+ `no` reaches implement.prototype.testing, which must report each once and
10
+ needs no chunk for the rest. A slice with no such criterion is not tested by hand, and
11
+ nothing rests to say so.
12
+
13
+ Background:
14
+ Given the shipped workflows, as gtd install scaffolds them
15
+ And an environment variable "GTD_QUALITYREVIEWS" set to ""
16
+ And an environment variable "GTD_FLAGMODE" set to "false"
17
+ And an environment variable "GTD_SLICEMAXCRITERIA" set to "2"
18
+ And a file "src/calc.ts" with:
19
+ """
20
+ export const add = (a: number, b: number) => a + b
21
+ """
22
+ And the working tree is committed as "feat: add calculator"
23
+ And a file "TODO.md" with:
24
+ """
25
+ # Add subtract
26
+
27
+ subtract(a, b) returns the difference.
28
+ """
29
+ And step "unwind" changes nothing
30
+ And step "start-gate.check" changes nothing
31
+ And step "design.gate.answer" changes nothing
32
+ And step "seam.check" changes nothing
33
+ And step "implement.applying" runs its script
34
+ And step "implement.health.check" changes nothing
35
+ And step "implement.closing" runs its script
36
+
37
+ Scenario: the testing turn skips a tagged criterion, which the judge is never asked about
38
+ Given step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
39
+ """
40
+ # Requirements
41
+
42
+ ## Acceptance Criteria
43
+
44
+ - AC-1: subtract(a, b) returns a - b.
45
+ - AC-2 (no hands-on): the build prompt names subtract.
46
+ """
47
+ And step "seam.naive" writes "src/calc.test.ts" with:
48
+ """
49
+ it("[AC-1] subtracts", () => {})
50
+ it("[AC-2] names subtract", () => {})
51
+ """
52
+ And judge step "implement.prototype.observable", when its questions contain "criterion AC-2 describes", answers:
53
+ """
54
+ [{"id":"AC-1","answer":"no","p":0.9},{"id":"AC-2","answer":"no","p":0.9}]
55
+ """
56
+ And judge step "implement.prototype.observable", when its questions contain "criterion AC-1 describes", answers:
57
+ """
58
+ [{"id":"AC-1","answer":"yes","p":0.9}]
59
+ """
60
+ And step "implement.prototype.testing" is prompted with "Skip AC-2: no person can observe them"
61
+ And step "implement.prototype.testing" writes ".gtd/PROTOTYPE.md" with:
62
+ """
63
+ ## AC-1: pass
64
+
65
+ Printed 2.
66
+ """
67
+ When the process is driven
68
+ Then the process rests at "build.review.reviewing"
69
+ And the commit subjects end with:
70
+ """
71
+ gtd(check): implement.health.check → implement.prototype.observable
72
+ gtd(judge): implement.prototype.observable → implement.prototype.testing
73
+ gtd(agent): implement.prototype.testing → implement.closing
74
+ gtd(check): implement.closing → build.review.reviewing
75
+ """
76
+
77
+ Scenario: a criterion the judge finds no person can observe is skipped like a tagged one
78
+ Given step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
79
+ """
80
+ # Requirements
81
+
82
+ ## Acceptance Criteria
83
+
84
+ - AC-1: subtract(a, b) returns a - b.
85
+ - AC-2: add is unchanged.
86
+ """
87
+ And step "seam.naive" writes "src/calc.test.ts" with:
88
+ """
89
+ it("[AC-1] subtracts", () => {})
90
+ it("[AC-2] adds", () => {})
91
+ """
92
+ And judge step "implement.prototype.observable" answers:
93
+ """
94
+ [{"id":"AC-1","answer":"yes","p":0.9},{"id":"AC-2","answer":"no","p":0.9}]
95
+ """
96
+ And step "implement.prototype.testing" is prompted with "Skip AC-2: no person can observe them"
97
+ And step "implement.prototype.testing" writes ".gtd/PROTOTYPE.md" with:
98
+ """
99
+ ## AC-1: pass
100
+
101
+ Printed 2.
102
+ """
103
+ When the process is driven
104
+ Then the process rests at "build.review.reviewing"
105
+ And the commit subjects end with:
106
+ """
107
+ gtd(judge): implement.prototype.observable → implement.prototype.testing
108
+ gtd(agent): implement.prototype.testing → implement.closing
109
+ gtd(check): implement.closing → build.review.reviewing
110
+ """
111
+
112
+ Scenario: a criterion the judge gives no verdict on is tested by hand
113
+ Given step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
114
+ """
115
+ # Requirements
116
+
117
+ ## Acceptance Criteria
118
+
119
+ - AC-1: subtract(a, b) returns a - b.
120
+ - AC-2: add is unchanged.
121
+ """
122
+ And step "seam.naive" writes "src/calc.test.ts" with:
123
+ """
124
+ it("[AC-1] subtracts", () => {})
125
+ it("[AC-2] adds", () => {})
126
+ """
127
+ And judge step "implement.prototype.observable" answers:
128
+ """
129
+ [{"id":"AC-2","answer":"no","p":0.9}]
130
+ """
131
+ And step "implement.prototype.testing" is prompted with "Skip AC-2: no person can observe them"
132
+ And step "implement.prototype.testing" writes ".gtd/PROTOTYPE.md" with:
133
+ """
134
+ ## AC-1: pass
135
+
136
+ Printed 2.
137
+ """
138
+ When the process is driven
139
+ Then the process rests at "build.review.reviewing"
140
+ And the commit subjects end with:
141
+ """
142
+ gtd(judge): implement.prototype.observable → implement.prototype.testing
143
+ gtd(agent): implement.prototype.testing → implement.closing
144
+ gtd(check): implement.closing → build.review.reviewing
145
+ """
146
+
147
+ Scenario: a judge landing without a verdict tests every untagged criterion by hand
148
+ Given step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
149
+ """
150
+ # Requirements
151
+
152
+ ## Acceptance Criteria
153
+
154
+ - AC-1: subtract(a, b) returns a - b.
155
+ - AC-2: add is unchanged.
156
+ """
157
+ And step "seam.naive" writes "src/calc.test.ts" with:
158
+ """
159
+ it("[AC-1] subtracts", () => {})
160
+ it("[AC-2] adds", () => {})
161
+ """
162
+ And judge step "implement.prototype.observable" answers:
163
+ """
164
+ []
165
+ """
166
+ And step "implement.prototype.testing" writes ".gtd/PROTOTYPE.md" with:
167
+ """
168
+ ## AC-1: pass
169
+
170
+ Printed 2.
171
+ """
172
+ Then driving the process is refused with "exactly one chunk headed `## <ID>: pass|fail|blocked` for AC-2"
173
+
174
+ Scenario: a report missing a criterion the judge found observable is refused
175
+ Given step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
176
+ """
177
+ # Requirements
178
+
179
+ ## Acceptance Criteria
180
+
181
+ - AC-1: subtract(a, b) returns a - b.
182
+ - AC-2: subtract prints a warning for negative results.
183
+ """
184
+ And step "seam.naive" writes "src/calc.test.ts" with:
185
+ """
186
+ it("[AC-1] subtracts", () => {})
187
+ it("[AC-2] warns", () => {})
188
+ """
189
+ And judge step "implement.prototype.observable" answers:
190
+ """
191
+ [{"id":"AC-1","answer":"yes","p":0.9},{"id":"AC-2","answer":"yes","p":0.9}]
192
+ """
193
+ And step "implement.prototype.testing" writes ".gtd/PROTOTYPE.md" with:
194
+ """
195
+ ## AC-1: pass
196
+
197
+ Printed 2.
198
+ """
199
+ Then driving the process is refused with "exactly one chunk headed `## <ID>: pass|fail|blocked` for AC-2"
200
+
201
+ Scenario: a change with no observable criterion skips the hands-on test without resting
202
+ Given step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
203
+ """
204
+ # Requirements
205
+
206
+ ## Acceptance Criteria
207
+
208
+ - AC-1: add is unchanged.
209
+ """
210
+ And step "seam.naive" writes "src/calc.test.ts" with:
211
+ """
212
+ it("[AC-1] adds", () => {})
213
+ """
214
+ And judge step "implement.prototype.observable" answers:
215
+ """
216
+ [{"id":"AC-1","answer":"no","p":0.9}]
217
+ """
218
+ When the process is driven
219
+ Then the process rests at "build.review.reviewing"
220
+ And the commit subjects end with:
221
+ """
222
+ gtd(check): implement.health.check → implement.prototype.observable
223
+ gtd(judge): implement.prototype.observable → implement.closing
224
+ gtd(check): implement.closing → build.review.reviewing
225
+ """
226
+
227
+ Scenario: a change whose every criterion is tagged is not tested by hand or judged
228
+ Given step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
229
+ """
230
+ # Requirements
231
+
232
+ ## Acceptance Criteria
233
+
234
+ - AC-1 (no hands-on): the build prompt names subtract.
235
+ - AC-2 (no hands-on): the review prompt names subtract.
236
+ """
237
+ And step "seam.naive" writes "src/calc.test.ts" with:
238
+ """
239
+ it("[AC-1] names subtract in the build", () => {})
240
+ it("[AC-2] names subtract in the review", () => {})
241
+ """
242
+ When the process is driven
243
+ Then the process rests at "build.review.reviewing"
244
+ And the commit subjects end with:
245
+ """
246
+ gtd(check): implement.health.check → implement.closing
247
+ gtd(check): implement.closing → build.review.reviewing
248
+ """
249
+
250
+ Scenario: each slice's hands-on test judges its own criteria afresh
251
+ Given step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
252
+ """
253
+ # Requirements
254
+
255
+ ## Acceptance Criteria
256
+
257
+ - AC-1: subtract(a, b) returns a - b.
258
+ - AC-2 (no hands-on): the build prompt names subtract.
259
+ - AC-3: the review prompt names subtract.
260
+ """
261
+ And step "design.slicing" writes ".gtd/SLICES.md" with:
262
+ """
263
+ # Slices
264
+
265
+ ## Prompts
266
+
267
+ - AC-2
268
+ - AC-3
269
+
270
+ ## Subtract
271
+
272
+ - AC-1
273
+ """
274
+ And step "seam.naive", when prompted with "This slice builds AC-2, AC-3 only", writes "src/prompts.test.ts" with:
275
+ """
276
+ it("[AC-2] names subtract in the build", () => {})
277
+ it("[AC-3] names subtract in the review", () => {})
278
+ """
279
+ And step "seam.naive", when prompted with "This slice builds AC-1 only", writes "src/calc.test.ts" with:
280
+ """
281
+ it("[AC-1] subtracts", () => {})
282
+ """
283
+ And judge step "implement.prototype.observable", when its questions contain "criterion AC-3 describes", answers:
284
+ """
285
+ [{"id":"AC-3","answer":"no","p":0.9}]
286
+ """
287
+ And judge step "implement.prototype.observable", when its questions contain "criterion AC-1 describes", answers:
288
+ """
289
+ [{"id":"AC-1","answer":"yes","p":0.9}]
290
+ """
291
+ And step "implement.prototype.testing" writes ".gtd/PROTOTYPE.md" with:
292
+ """
293
+ ## AC-1: pass
294
+
295
+ Printed 2.
296
+ """
297
+ When the process is driven
298
+ Then the process rests at "build.review.reviewing"
299
+ And the commit subjects end with:
300
+ """
301
+ gtd(check): implement.health.check → implement.prototype.observable
302
+ gtd(judge): implement.prototype.observable → implement.closing
303
+ gtd(check): implement.closing → seam.naive
304
+ gtd(agent): seam.naive → seam.check
305
+ gtd(check): seam.check → implement.applying
306
+ gtd(check): implement.applying → implement.health.check
307
+ gtd(check): implement.health.check → implement.prototype.observable
308
+ gtd(judge): implement.prototype.observable → implement.prototype.testing
309
+ gtd(agent): implement.prototype.testing → implement.closing
310
+ gtd(check): implement.closing → build.review.reviewing
311
+ """
312
+
313
+ Scenario: the tag is frozen once design is settled
314
+ Given step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
315
+ """
316
+ # Requirements
317
+
318
+ ## Acceptance Criteria
319
+
320
+ - AC-1: subtract(a, b) returns a - b.
321
+ """
322
+ And step "seam.naive" writes "src/calc.test.ts" with:
323
+ """
324
+ it("[AC-1] subtracts", () => {})
325
+ """
326
+ And judge step "implement.prototype.observable" answers:
327
+ """
328
+ [{"id":"AC-1","answer":"yes","p":0.9}]
329
+ """
330
+ And step "implement.prototype.testing" writes ".gtd/PROTOTYPE.md" with:
331
+ """
332
+ ## AC-1: fail
333
+
334
+ Printed 4.
335
+ """
336
+ And step "implement.prototype.fix.fixing" writes ".gtd/REQUIREMENTS.md" with:
337
+ """
338
+ # Requirements
339
+
340
+ ## Acceptance Criteria
341
+
342
+ - AC-1 (no hands-on): subtract(a, b) returns a - b.
343
+ """
344
+ Then driving the process is refused with "criteria-frozen"
@@ -51,10 +51,6 @@ Feature: each quality lens runs on its own model hint
51
51
  And step "implement.applying" runs its script
52
52
  And step "implement.health.check" changes nothing
53
53
  And step "implement.closing" runs its script
54
- And judge step "implement.coverage" answers:
55
- """
56
- [{"id":"AC-1","answer":"yes","p":0.9}]
57
- """
58
54
 
59
55
  Scenario: a hinted lens runs on its hint, every other lens on its default
60
56
  When the process is driven
@@ -53,10 +53,6 @@ Feature: the quality lap's findings are triaged before the review
53
53
  And step "implement.applying" runs its script
54
54
  And step "implement.health.check" changes nothing
55
55
  And step "implement.closing" runs its script
56
- And judge step "implement.coverage" answers:
57
- """
58
- [{"id":"AC-1","answer":"yes","p":0.9}]
59
- """
60
56
  And step "build.quality.correctness.reviewing" writes ".gtd/QUALITY.md" with:
61
57
  """
62
58
  # Quality
@@ -113,7 +109,9 @@ Feature: the quality lap's findings are triaged before the review
113
109
  And the commit "gtd(judge): build.quality.triage → build.quality.sorting" has a body containing "Gtd-Mark: noise=Q2 p=0.85 add could be a method"
114
110
  And ".gtd/REVIEW.md" contains:
115
111
  """
116
- ## AC-1 ignores floating point
112
+ ## Findings
113
+
114
+ ### AC-1 ignores floating point
117
115
 
118
116
  _critical: judge unsure_
119
117
 
@@ -129,9 +127,9 @@ Feature: the quality lap's findings are triaged before the review
129
127
  - [ ] won't fix
130
128
  - [ ] _your answer_
131
129
 
132
- ## Fixed automatically
130
+ ## Walkthrough
133
131
 
134
- - subtract has no negative test (
132
+ ### Subtract
135
133
  """
136
134
  And ".gtd/REVIEW.md" contains the short hash of the commit "gtd(agent): build.fix.quality.fixing → build.health.check"
137
135
  And ".gtd/REVIEW.md" contains:
@@ -235,7 +233,7 @@ Feature: the quality lap's findings are triaged before the review
235
233
  And ".gtd/QUALITY.md" does not exist
236
234
  And ".gtd/REVIEW.md" contains:
237
235
  """
238
- ## add could be a method
236
+ ### add could be a method
239
237
 
240
238
  _critical: judge unsure_
241
239
 
@@ -57,10 +57,6 @@ Feature: a naive pass the judge rules land is itself the implementation
57
57
  And step "implement.applying" runs its script
58
58
  And step "implement.health.check" changes nothing
59
59
  And step "implement.closing" runs its script
60
- And judge step "implement.coverage" answers:
61
- """
62
- [{"id":"AC-1","answer":"yes","p":0.9}]
63
- """
64
60
  And step "build.quality.correctness.reviewing" changes nothing
65
61
 
66
62
  Scenario: a land judgment applies the naive pass and runs from idle to the review gate with no rebuild
@@ -79,8 +75,7 @@ Feature: a naive pass the judge rules land is itself the implementation
79
75
  gtd(check): seam.check → seam.judge
80
76
  gtd(judge): seam.judge → implement.applying
81
77
  gtd(check): implement.applying → implement.health.check
82
- gtd(check): implement.health.check → implement.coverage
83
- gtd(judge): implement.coverage → implement.closing
78
+ gtd(check): implement.health.check → implement.closing
84
79
  gtd(check): implement.closing → build.quality.correctness.reviewing
85
80
  gtd(agent): build.quality.correctness.reviewing → build.review.reviewing
86
81
  """
@@ -47,7 +47,7 @@ Feature: past its round cap the hands-on test rests at a person's gate
47
47
  And step "seam.check" changes nothing
48
48
  And step "implement.applying" runs its script
49
49
  And step "implement.health.check" changes nothing
50
- And judge step "implement.coverage" answers:
50
+ And judge step "implement.prototype.observable" answers:
51
51
  """
52
52
  [{"id":"AC-1","answer":"yes","p":0.9},{"id":"AC-2","answer":"yes","p":0.9}]
53
53
  """
@@ -1,10 +1,11 @@
1
1
  @inmem
2
- Feature: every criterion is tested by hand before the quality lap
2
+ Feature: every observable criterion is tested by hand before the quality lap
3
3
 
4
- Once coverage is judged, implement.prototype.testing uses the slice the way
5
- a person would and writes .gtd/PROTOTYPE.md, one chunk per criterion headed
6
- `## AC-<n>: pass|fail|blocked`, plus one per problem found beside them. A
7
- failure goes to implement.prototype.fix.fixing and is tested again; only a clean
4
+ Once the suite is green, implement.prototype.observable judges which
5
+ criteria a person can observe, and implement.prototype.testing uses the
6
+ slice the way a person would and writes .gtd/PROTOTYPE.md, one chunk per
7
+ such criterion headed `## AC-<n>: pass|fail|blocked`, plus one per problem
8
+ found beside them. A failure goes to implement.prototype.fix.fixing and is tested again; only a clean
8
9
  report closes the slice. Past `prototypeRounds` fix rounds, or with nothing a
9
10
  fixer can take, a person decides at implement.prototype.open.
10
11
 
@@ -48,7 +49,7 @@ Feature: every criterion is tested by hand before the quality lap
48
49
  And step "seam.check" changes nothing
49
50
  And step "implement.applying" runs its script
50
51
  And step "implement.health.check" changes nothing
51
- And judge step "implement.coverage" answers:
52
+ And judge step "implement.prototype.observable" answers:
52
53
  """
53
54
  [{"id":"AC-1","answer":"yes","p":0.9},{"id":"AC-2","answer":"yes","p":0.9}]
54
55
  """
@@ -57,7 +58,7 @@ Feature: every criterion is tested by hand before the quality lap
57
58
  Scenario: the testing turn is told to use every criterion for real, in a disposable place
58
59
  When the process is driven
59
60
  Then the process rests at "implement.prototype.testing"
60
- And the last commit subject is "gtd(judge): implement.coverage → implement.prototype.testing"
61
+ And the last commit subject is "gtd(judge): implement.prototype.observable → implement.prototype.testing"
61
62
  And the resting step's content contains "Running the test suite is not this"
62
63
  And the resting step's content contains "against the user's real data or this working tree"
63
64
  And the resting step's content contains "`## AC-<n>: pass`"
@@ -79,7 +80,7 @@ Feature: every criterion is tested by hand before the quality lap
79
80
  Then the process rests at "build.quality.correctness.reviewing"
80
81
  And the commit subjects end with:
81
82
  """
82
- gtd(judge): implement.coverage → implement.prototype.testing
83
+ gtd(judge): implement.prototype.observable → implement.prototype.testing
83
84
  gtd(agent): implement.prototype.testing → implement.closing
84
85
  gtd(check): implement.closing → build.quality.correctness.reviewing
85
86
  """
@@ -121,7 +122,7 @@ Feature: every criterion is tested by hand before the quality lap
121
122
  Then the process rests at "build.quality.correctness.reviewing"
122
123
  And the commit subjects end with:
123
124
  """
124
- gtd(judge): implement.coverage → implement.prototype.testing
125
+ gtd(judge): implement.prototype.observable → implement.prototype.testing
125
126
  gtd(agent): implement.prototype.testing → implement.prototype.fix.fixing
126
127
  gtd(agent): implement.prototype.fix.fixing → implement.prototype.health.check
127
128
  gtd(check): implement.prototype.health.check → implement.prototype.testing