@pmelab/gtd 48.0.0 → 50.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 (45) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +31 -20
  3. package/dist/chunks/{reserved-DF1HD6jL.mjs → reserved-CdOzKFVX.mjs} +150 -24
  4. package/dist/chunks/{review-Bv40kZu9.mjs → review-BChXEl2Y.mjs} +132 -24
  5. package/dist/chunks/{steering-D7hWeMgE.mjs → steering-DtUVUz9l.mjs} +49 -13
  6. package/dist/chunks/{tail-D89fU_wf.mjs → tail-DRM2eC1z.mjs} +1 -1
  7. package/dist/gtd.bundle.mjs +22 -5
  8. package/dist/steering.mjs +2 -2
  9. package/dist/testkit.mjs +1 -1
  10. package/dist/web/main.js +27 -3
  11. package/dist/workflow-kit.mjs +1 -1
  12. package/dist/workflows/cleanup.mjs +2 -2
  13. package/dist/workflows/feature.mjs +16 -9
  14. package/dist/workflows/fix.mjs +3 -3
  15. package/dist/workflows/review.mjs +3 -3
  16. package/dist/workflows/rollout.mjs +1 -1
  17. package/dist/workflows.mjs +338 -62
  18. package/package.json +1 -1
  19. package/src/steering/index.ts +2 -0
  20. package/src/steering/review.test.ts +87 -0
  21. package/src/steering/review.ts +75 -8
  22. package/src/workflows/feature/coverage.feature +3 -3
  23. package/src/workflows/feature/fast-path.feature +2 -2
  24. package/src/workflows/feature/feature.ts +10 -3
  25. package/src/workflows/feature/flag-mode.feature +2 -2
  26. package/src/workflows/feature/lens-review.feature +128 -13
  27. package/src/workflows/feature/one-step-land.feature +2 -2
  28. package/src/workflows/feature/refactor-absorbs.feature +2 -2
  29. package/src/workflows/feature/refactor-first.feature +2 -2
  30. package/src/workflows/feature/refactor-rebuild.feature +2 -2
  31. package/src/workflows/feature/refactor-review.feature +6 -6
  32. package/src/workflows/feature/review-answers.feature +51 -5
  33. package/src/workflows/feature/review-gate.feature +23 -6
  34. package/src/workflows/feature/reviewer-walkthrough.feature +240 -0
  35. package/src/workflows/feature/seam-rejection.feature +2 -2
  36. package/src/workflows/feature/seam.feature +2 -2
  37. package/src/workflows/feature/severity-budget.feature +111 -0
  38. package/src/workflows/feature/severity-sorted-review.feature +197 -0
  39. package/src/workflows/feature/slice-findings.feature +68 -5
  40. package/src/workflows/feature/slicing.feature +6 -6
  41. package/src/workflows/feature/standards.feature +29 -1
  42. package/src/workflows/shared/review.ts +226 -25
  43. package/src/workflows/shared/steps.ts +3 -2
  44. package/src/workflows/shared/text.test.ts +216 -0
  45. package/src/workflows/shared/text.ts +201 -19
@@ -0,0 +1,197 @@
1
+ @inmem
2
+ Feature: the final review lists what matters most first
3
+
4
+ Before the review rests, the judge rates every chunk the reviewer wrote — a
5
+ walkthrough chunk or a carried quality finding — on the same four questions
6
+ as a human's note (`build.review.ranking`): critical (security, or a one-way
7
+ door), should (a contract, or a new concept), could. The review lists them
8
+ in that order, security before one-way doors, each led by its tier and
9
+ reason. A chunk the judge cannot rate is critical, so it is shown first.
10
+
11
+ Background:
12
+ Given the shipped workflows, as gtd install scaffolds them
13
+ And an environment variable "GTD_QUALITYREVIEWS" set to "correctness"
14
+ And an environment variable "GTD_FLAGMODE" set to "false"
15
+ And a file "src/calc.ts" with:
16
+ """
17
+ export const add = (a: number, b: number) => a + b
18
+ """
19
+ And the working tree is committed as "feat: add calculator"
20
+ And a file "TODO.md" with:
21
+ """
22
+ # Add subtract
23
+
24
+ subtract(a, b) returns the difference.
25
+ """
26
+ And step "unwind" changes nothing
27
+ And step "start-gate.check" changes nothing
28
+ And step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
29
+ """
30
+ # Requirements
31
+
32
+ ## Acceptance Criteria
33
+
34
+ - AC-1: subtract(a, b) returns a - b.
35
+ """
36
+ And step "design.gate.answer" changes nothing
37
+ And step "seam.naive" writes "src/calc.test.ts" with:
38
+ """
39
+ it("[AC-1] subtracts", () => {})
40
+ """
41
+ And step "seam.naive" writes "src/calc.ts" with:
42
+ """
43
+ export const add = (a: number, b: number) => a + b
44
+ export const subtract = (a: number, b: number) => a - b
45
+ """
46
+ And step "seam.check" changes nothing
47
+ And step "implement.applying" runs its script
48
+ And step "implement.health.check" changes nothing
49
+ And step "implement.closing" runs its script
50
+ And judge step "implement.coverage" answers:
51
+ """
52
+ [{"id":"AC-1","answer":"yes","p":0.9}]
53
+ """
54
+ And step "build.quality.correctness.reviewing" writes ".gtd/QUALITY.md" with:
55
+ """
56
+ # Quality
57
+
58
+ ## AC-1 ignores floating point
59
+
60
+ Should subtract round? The criterion does not say.
61
+ """
62
+ And judge step "build.quality.triage" answers:
63
+ """
64
+ [{"id":"Q1","answer":"design","p":0.9}]
65
+ """
66
+ And step "build.quality.sorting" runs its script
67
+ And step "build.quality.closing" runs its script
68
+ And step "build.review.carrying" runs its script
69
+
70
+ Scenario: security and one-way doors come first, a carried finding sorted among the rest
71
+ Given step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
72
+ """
73
+ # Review: abc1234
74
+
75
+ <!-- base: 0000000 -->
76
+
77
+ ## Subtract
78
+
79
+ The new export.
80
+
81
+ - [ ] ./src/calc.ts#2-2 — subtract(a, b)
82
+
83
+ ## Session token
84
+
85
+ - [ ] ./src/calc.ts#1-1 — reads the caller's token
86
+
87
+ ## AC-1 ignores floating point
88
+
89
+ - [ ] ./src/calc.ts#2-2 — returns the raw difference
90
+
91
+ ## Saved format
92
+
93
+ - [ ] ./src/calc.ts#1-2 — what callers persist
94
+ """
95
+ And judge step "build.review.ranking" answers:
96
+ """
97
+ [{"id":"C1.security","answer":"no","p":0.9},{"id":"C1.reversibility","answer":"two-way","p":0.9},{"id":"C1.blastRadius","answer":"local","p":0.9},{"id":"C1.newConcept","answer":"no","p":0.9},{"id":"C2.security","answer":"yes","p":0.9},{"id":"C2.reversibility","answer":"two-way","p":0.9},{"id":"C2.blastRadius","answer":"module","p":0.9},{"id":"C2.newConcept","answer":"no","p":0.9},{"id":"C3.security","answer":"no","p":0.9},{"id":"C3.reversibility","answer":"two-way","p":0.9},{"id":"C3.blastRadius","answer":"contract","p":0.9},{"id":"C3.newConcept","answer":"no","p":0.9},{"id":"C4.security","answer":"no","p":0.9},{"id":"C4.reversibility","answer":"one-way","p":0.9},{"id":"C4.blastRadius","answer":"contract","p":0.9},{"id":"C4.newConcept","answer":"no","p":0.9}]
98
+ """
99
+ When the process is driven
100
+ Then the process rests at "build.review.await-review"
101
+ And ".gtd/REVIEW.md" contains:
102
+ """
103
+ ## Session token
104
+
105
+ _critical: security_
106
+
107
+ - [ ] ./src/calc.ts#1-1 — reads the caller's token
108
+
109
+ ## Saved format
110
+
111
+ _critical: one-way door_
112
+
113
+ - [ ] ./src/calc.ts#1-2 — what callers persist
114
+
115
+ ## AC-1 ignores floating point
116
+
117
+ _should: contract_
118
+
119
+ Should subtract round? The criterion does not say.
120
+ """
121
+ And ".gtd/REVIEW.md" contains:
122
+ """
123
+ - [ ] _your answer_
124
+
125
+ ## Subtract
126
+
127
+ _could_
128
+
129
+ The new export.
130
+ """
131
+ And the commit "gtd(judge): build.review.ranking → build.review.carrying" has a body containing "Gtd-Judge:"
132
+ And the commit subjects end with:
133
+ """
134
+ gtd(agent): build.review.reviewing → build.review.ranking
135
+ gtd(judge): build.review.ranking → build.review.carrying
136
+ gtd(check): build.review.carrying → build.review.await-review
137
+ """
138
+
139
+ Scenario: a chunk the judge is unsure about is listed as critical
140
+ Given step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
141
+ """
142
+ # Review: abc1234
143
+
144
+ <!-- base: 0000000 -->
145
+
146
+ ## Subtract
147
+
148
+ The new export.
149
+
150
+ - [ ] ./src/calc.ts#2-2 — subtract(a, b)
151
+
152
+ ## Session token
153
+
154
+ - [ ] ./src/calc.ts#1-1 — reads the caller's token
155
+
156
+ ## AC-1 ignores floating point
157
+
158
+ - [ ] ./src/calc.ts#2-2 — returns the raw difference
159
+
160
+ ## Saved format
161
+
162
+ - [ ] ./src/calc.ts#1-2 — what callers persist
163
+ """
164
+ And judge step "build.review.ranking" answers:
165
+ """
166
+ [{"id":"C1.security","answer":"no","p":0.9},{"id":"C1.reversibility","answer":"two-way","p":0.9},{"id":"C1.blastRadius","answer":"local","p":0.9},{"id":"C1.newConcept","answer":"no","p":0.9},{"id":"C2.security","answer":"no","p":0.4},{"id":"C2.reversibility","answer":"two-way","p":0.9},{"id":"C2.blastRadius","answer":"local","p":0.9},{"id":"C2.newConcept","answer":"no","p":0.9},{"id":"C3.security","answer":"no","p":0.9},{"id":"C3.reversibility","answer":"two-way","p":0.9},{"id":"C3.blastRadius","answer":"contract","p":0.9},{"id":"C3.newConcept","answer":"no","p":0.9},{"id":"C4.security","answer":"no","p":0.9},{"id":"C4.reversibility","answer":"two-way","p":0.9},{"id":"C4.blastRadius","answer":"local","p":0.9},{"id":"C4.newConcept","answer":"yes","p":0.9}]
167
+ """
168
+ When the process is driven
169
+ Then the process rests at "build.review.await-review"
170
+ And ".gtd/REVIEW.md" contains:
171
+ """
172
+ # Review: abc1234
173
+
174
+ <!-- base: 0000000 -->
175
+
176
+ ## Session token
177
+
178
+ _critical: judge unsure_
179
+ """
180
+ And ".gtd/REVIEW.md" contains:
181
+ """
182
+ ## AC-1 ignores floating point
183
+
184
+ _should: contract_
185
+ """
186
+ And ".gtd/REVIEW.md" contains:
187
+ """
188
+ ## Saved format
189
+
190
+ _should: new concept_
191
+ """
192
+ And ".gtd/REVIEW.md" contains:
193
+ """
194
+ ## Subtract
195
+
196
+ _could_
197
+ """
@@ -70,7 +70,11 @@ Feature: every slice's quality lap is triaged, and its leftovers wait for the re
70
70
  And step "build.quality.sorting" runs its script
71
71
  And step "build.quality.closing" runs its script
72
72
  And step "build.health.check" changes nothing
73
- And step "build.review.composing" runs its script
73
+ And step "build.review.carrying" runs its script
74
+ And judge step "build.review.ranking" answers:
75
+ """
76
+ []
77
+ """
74
78
 
75
79
  Scenario: a finding questioning a criterion reaches the final review, never the fixer
76
80
  Given step "build.quality.correctness.reviewing" writes ".gtd/QUALITY.md" with:
@@ -85,6 +89,25 @@ Feature: every slice's quality lap is triaged, and its leftovers wait for the re
85
89
  """
86
90
  [{"id":"Q1","answer":"design","p":0.9}]
87
91
  """
92
+ And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
93
+ """
94
+ # Review: abc1234
95
+
96
+ <!-- base: 0000000 -->
97
+
98
+ ## Subtract and multiply
99
+
100
+ - [ ] ./src/sub.test.ts#1-1 — subtract
101
+ - [ ] ./src/mul.test.ts#1-1 — multiply
102
+
103
+ ## AC-1 ignores floating point
104
+
105
+ - [ ] ./src/sub.test.ts#1-1 — where it applies
106
+
107
+ ## AC-1 ignores floating point (2)
108
+
109
+ - [ ] ./src/sub.test.ts#1-1 — where it applies
110
+ """
88
111
  When the process is driven
89
112
  Then the process rests at "build.review.await-review"
90
113
  And no commit body contains "build.fix.quality.fixing"
@@ -93,6 +116,8 @@ Feature: every slice's quality lap is triaged, and its leftovers wait for the re
93
116
  """
94
117
  ## AC-1 ignores floating point
95
118
 
119
+ _critical: judge unsure_
120
+
96
121
  _From slice 1, lens correctness._
97
122
 
98
123
  Should subtract round? The criterion does not say.
@@ -101,6 +126,8 @@ Feature: every slice's quality lap is triaged, and its leftovers wait for the re
101
126
  """
102
127
  ## AC-1 ignores floating point (2)
103
128
 
129
+ _critical: judge unsure_
130
+
104
131
  _From slice 2, lens correctness._
105
132
  """
106
133
  And the commit subjects end with:
@@ -117,8 +144,10 @@ Feature: every slice's quality lap is triaged, and its leftovers wait for the re
117
144
  gtd(check): implement.closing → build.quality.correctness.reviewing
118
145
  gtd(agent): build.quality.correctness.reviewing → build.quality.triage
119
146
  gtd(judge): build.quality.triage → build.quality.sorting
120
- gtd(check): build.quality.sorting → build.review.composing
121
- gtd(check): build.review.composing → build.review.await-review
147
+ gtd(check): build.quality.sorting → build.review.reviewing
148
+ gtd(agent): build.review.reviewing → build.review.ranking
149
+ gtd(judge): build.review.ranking → build.review.carrying
150
+ gtd(check): build.review.carrying → build.review.await-review
122
151
  """
123
152
 
124
153
  Scenario: a mechanical finding the fix cap leaves in an early slice is carried, never escalated
@@ -135,6 +164,25 @@ Feature: every slice's quality lap is triaged, and its leftovers wait for the re
135
164
  [{"id":"Q1","answer":"mechanical","p":0.9}]
136
165
  """
137
166
  And step "build.fix.quality.fixing" changes nothing
167
+ And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
168
+ """
169
+ # Review: abc1234
170
+
171
+ <!-- base: 0000000 -->
172
+
173
+ ## Subtract and multiply
174
+
175
+ - [ ] ./src/sub.test.ts#1-1 — subtract
176
+ - [ ] ./src/mul.test.ts#1-1 — multiply
177
+
178
+ ## subtract has no negative test
179
+
180
+ - [ ] ./src/sub.test.ts#1-1 — where it applies
181
+
182
+ ## subtract has no negative test (2)
183
+
184
+ - [ ] ./src/sub.test.ts#1-1 — where it applies
185
+ """
138
186
  When the process is driven
139
187
  Then the process rests at "build.review.await-review"
140
188
  And no commit body contains "build.health.describe"
@@ -142,6 +190,8 @@ Feature: every slice's quality lap is triaged, and its leftovers wait for the re
142
190
  """
143
191
  ## subtract has no negative test
144
192
 
193
+ _critical: judge unsure_
194
+
145
195
  _From slice 1, lens correctness._
146
196
 
147
197
  _The fixer left this unresolved._
@@ -168,8 +218,10 @@ Feature: every slice's quality lap is triaged, and its leftovers wait for the re
168
218
  gtd(agent): build.fix.quality.fixing
169
219
  gtd(agent): build.fix.quality.fixing → build.health.check
170
220
  gtd(check): build.health.check → build.quality.closing
171
- gtd(check): build.quality.closing → build.review.composing
172
- gtd(check): build.review.composing → build.review.await-review
221
+ gtd(check): build.quality.closing → build.review.reviewing
222
+ gtd(agent): build.review.reviewing → build.review.ranking
223
+ gtd(judge): build.review.ranking → build.review.carrying
224
+ gtd(check): build.review.carrying → build.review.await-review
173
225
  """
174
226
 
175
227
  Scenario: the final review lists every slice's fixes with their commits
@@ -190,6 +242,17 @@ Feature: every slice's quality lap is triaged, and its leftovers wait for the re
190
242
  it("subtracts a larger number", () => {})
191
243
  """
192
244
  And step "build.fix.quality.fixing" deletes ".gtd/QUALITY.md"
245
+ And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
246
+ """
247
+ # Review: abc1234
248
+
249
+ <!-- base: 0000000 -->
250
+
251
+ ## Subtract and multiply
252
+
253
+ - [ ] ./src/sub.test.ts#1-1 — subtract
254
+ - [ ] ./src/mul.test.ts#1-1 — multiply
255
+ """
193
256
  When the process is driven
194
257
  Then the process rests at "build.review.await-review"
195
258
  And ".gtd/REVIEW.md" contains ", slice 1, lens correctness)"
@@ -51,7 +51,7 @@ Feature: a change with more criteria than the cap is built in coarse slices
51
51
  [{"id":"AC-1","answer":"yes","p":0.9},{"id":"AC-2","answer":"yes","p":0.9}]
52
52
  """
53
53
  When the process is driven
54
- Then the process rests at "build.review.composing"
54
+ Then the process rests at "build.review.reviewing"
55
55
  And the commit subjects end with:
56
56
  """
57
57
  gtd(human): design.gate.answer → seam.naive
@@ -60,7 +60,7 @@ Feature: a change with more criteria than the cap is built in coarse slices
60
60
  gtd(check): implement.applying → implement.health.check
61
61
  gtd(check): implement.health.check → implement.coverage
62
62
  gtd(judge): implement.coverage → implement.closing
63
- gtd(check): implement.closing → build.review.composing
63
+ gtd(check): implement.closing → build.review.reviewing
64
64
  """
65
65
  And the output lines of gtd "slices" start with:
66
66
  """
@@ -112,7 +112,7 @@ Feature: a change with more criteria than the cap is built in coarse slices
112
112
  [{"id":"AC-2","answer":"yes","p":0.9}]
113
113
  """
114
114
  When the process is driven
115
- Then the process rests at "build.review.composing"
115
+ Then the process rests at "build.review.reviewing"
116
116
  And the commit subjects end with:
117
117
  """
118
118
  gtd(agent): design.triage → design.gate.answer
@@ -129,7 +129,7 @@ Feature: a change with more criteria than the cap is built in coarse slices
129
129
  gtd(check): implement.applying → implement.health.check
130
130
  gtd(check): implement.health.check → implement.coverage
131
131
  gtd(judge): implement.coverage → implement.closing
132
- gtd(check): implement.closing → build.review.composing
132
+ gtd(check): implement.closing → build.review.reviewing
133
133
  """
134
134
  And the output lines of gtd "slices" start with:
135
135
  """
@@ -268,7 +268,7 @@ Feature: a change with more criteria than the cap is built in coarse slices
268
268
  """
269
269
  When gtd lands
270
270
  And the process is driven
271
- Then the process rests at "build.review.composing"
271
+ Then the process rests at "build.review.reviewing"
272
272
  And the commit subjects end with:
273
273
  """
274
274
  gtd(human): seam.steer → seam.naive
@@ -277,7 +277,7 @@ Feature: a change with more criteria than the cap is built in coarse slices
277
277
  gtd(check): implement.applying → implement.health.check
278
278
  gtd(check): implement.health.check → implement.coverage
279
279
  gtd(judge): implement.coverage → implement.closing
280
- gtd(check): implement.closing → build.review.composing
280
+ gtd(check): implement.closing → build.review.reviewing
281
281
  """
282
282
  And ".gtd/REQUIREMENTS.md" does not exist
283
283
  And ".gtd/SLICES.md" does not exist
@@ -67,7 +67,35 @@ Feature: the review learns standards from the human's answers
67
67
  Calculators read better as classes.
68
68
  """
69
69
  And step "build.quality.sorting" runs its script
70
- And step "build.review.composing" runs its script
70
+ And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
71
+ """
72
+ # Review: abc1234
73
+
74
+ <!-- base: 0000000 -->
75
+
76
+ ## Subtract
77
+
78
+ - [ ] ./src/calc.ts#2-2 — subtract(a, b)
79
+ """
80
+ And step "build.review.reviewing", when prompted with "- `## subtract has no class`", writes ".gtd/REVIEW.md" with:
81
+ """
82
+ # Review: abc1234
83
+
84
+ <!-- base: 0000000 -->
85
+
86
+ ## Subtract
87
+
88
+ - [ ] ./src/calc.ts#2-2 — subtract(a, b)
89
+
90
+ ## subtract has no class
91
+
92
+ - [ ] ./src/calc.ts#2-2 — a plain function
93
+ """
94
+ And step "build.review.carrying" runs its script
95
+ And judge step "build.review.ranking" answers:
96
+ """
97
+ []
98
+ """
71
99
  And judge step "build.quality.triage" answers:
72
100
  """
73
101
  [{"id":"Q1","answer":"design","p":0.9}]