@pmelab/gtd 54.0.0 → 56.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 (72) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +109 -104
  3. package/dist/chunks/{reserved-CQ7amcKG.mjs → reserved-B8EC-WE8.mjs} +124 -230
  4. package/dist/chunks/{review-CXzUXJHL.mjs → review-HdrX0FJ7.mjs} +30 -125
  5. package/dist/chunks/{steering-CLhu8C7q.mjs → steering-CCNvngSH.mjs} +256 -65
  6. package/dist/chunks/{tail-JZ9PAOwp.mjs → tail-BSLah2mA.mjs} +155 -63
  7. package/dist/gtd.bundle.mjs +259 -22
  8. package/dist/steering.mjs +2 -2
  9. package/dist/testkit.mjs +6 -6
  10. package/dist/web/main.css +1 -1
  11. package/dist/web/main.js +551 -66
  12. package/dist/workflow-kit.mjs +1 -1
  13. package/dist/workflows/cleanup.mjs +2 -2
  14. package/dist/workflows/feature.mjs +47 -102
  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 +614 -574
  19. package/package.json +1 -1
  20. package/skills/authoring/SKILL.md +3 -3
  21. package/src/cli/Cli.ts +5 -5
  22. package/src/edge/Edge.test.ts +1 -1
  23. package/src/steering/FORMATS.md +5 -1
  24. package/src/steering/SteeringFormats.test.ts +2 -2
  25. package/src/steering/contract.test.ts +1 -0
  26. package/src/steering/findings.test.ts +47 -0
  27. package/src/steering/findings.ts +350 -0
  28. package/src/steering/fixtures/findings/gate.md +34 -0
  29. package/src/steering/fixtures/findings/gate.read.json +87 -0
  30. package/src/steering/index.test.ts +2 -2
  31. package/src/steering/index.ts +4 -3
  32. package/src/steering/review.test.ts +1 -75
  33. package/src/steering/review.ts +1 -74
  34. package/src/workflow/compile.test.ts +1 -0
  35. package/src/workflows/feature/criteria-coverage.feature +104 -0
  36. package/src/workflows/feature/feature.test.ts +1 -1
  37. package/src/workflows/feature/feature.ts +17 -20
  38. package/src/workflows/feature/green.ts +2 -5
  39. package/src/workflows/feature/lens-review.feature +323 -171
  40. package/src/workflows/feature/naive-acceptance.feature +31 -32
  41. package/src/workflows/feature/prototype.ts +5 -8
  42. package/src/workflows/feature/refactor-absorbs.feature +1 -7
  43. package/src/workflows/feature/refactor-first.feature +2 -10
  44. package/src/workflows/feature/refactor-rebuild.feature +20 -36
  45. package/src/workflows/feature/refactor-review.feature +33 -117
  46. package/src/workflows/feature/refactor.test.ts +0 -2
  47. package/src/workflows/feature/refactor.ts +0 -1
  48. package/src/workflows/feature/review-gate.feature +6 -22
  49. package/src/workflows/feature/reviewer-walkthrough.feature +16 -103
  50. package/src/workflows/feature/seam.test.ts +19 -101
  51. package/src/workflows/feature/seam.ts +13 -89
  52. package/src/workflows/feature/standards.feature +75 -34
  53. package/src/workflows/fix/fix-lens-origin.feature +20 -7
  54. package/src/workflows/fix/fix-quality.feature +104 -23
  55. package/src/workflows/review/review-door.feature +62 -59
  56. package/src/workflows/shared/access.test.ts +1 -0
  57. package/src/workflows/shared/learn.test.ts +0 -14
  58. package/src/workflows/shared/learn.ts +1 -6
  59. package/src/workflows/shared/lenses.ts +149 -43
  60. package/src/workflows/shared/review.test.ts +30 -27
  61. package/src/workflows/shared/review.ts +29 -196
  62. package/src/workflows/shared/skills.test.ts +3 -1
  63. package/src/workflows/shared/steps.test.ts +9 -6
  64. package/src/workflows/shared/steps.ts +12 -3
  65. package/src/workflows/shared/tail.test.ts +20 -2
  66. package/src/workflows/shared/tail.ts +38 -16
  67. package/src/workflows/shared/text.test.ts +122 -294
  68. package/src/workflows/shared/text.ts +181 -358
  69. package/src/workflows/shared/vars.ts +1 -1
  70. package/src/workflows/feature/review-answers.feature +0 -324
  71. package/src/workflows/feature/severity-budget.feature +0 -116
  72. package/src/workflows/feature/severity-sorted-review.feature +0 -198
@@ -1,11 +1,10 @@
1
1
  @inmem
2
- Feature: a naive pass ends only when a test names every criterion and the suite is green
2
+ Feature: a naive pass ends only when its tests reach no file it added and the suite is green
3
3
 
4
- `seam.naive` writes behaviour-level acceptance tests, each naming its
5
- criterion's ID. A pass whose tests leave an ID out or import a file the
6
- pass added is sent back; `seam.check` then runs the suite with the kept
7
- pass applied, and a red run sends it back too, before the judge sees it.
8
- Three failed attempts rest at `seam.steer`.
4
+ `seam.naive` needs no test at all. A pass whose test imports a file the pass
5
+ added is sent back; `seam.check` then runs the suite with the kept pass
6
+ applied, and a red run sends it back too, before the judge sees it. Three
7
+ failed attempts rest at `seam.steer`.
9
8
 
10
9
  Background:
11
10
  Given the shipped workflows, as gtd install scaffolds them
@@ -44,15 +43,30 @@ Feature: a naive pass ends only when a test names every criterion and the suite
44
43
  export const subtract = (a: number, b: number) => a - b
45
44
  """
46
45
 
47
- Scenario: a pass whose tests leave a criterion's ID out is sent back, and an overrule runs the check and sticks
48
- Given step "seam.naive" writes "tests/calc.test.ts" with:
46
+ Scenario: a pass without a test goes on to the check and the judge
47
+ Given step "seam.check" changes nothing
48
+ When the process is driven
49
+ Then the process rests at "seam.judge"
50
+ And the commit subjects end with:
49
51
  """
50
- import { add, subtract } from "../src/calc.js"
51
- it("[AC-1] subtracts", () => expect(subtract(5, 3)).toBe(2))
52
+ gtd(human): design.gate.answer → seam.naive
53
+ gtd(agent): seam.naive → seam.check
54
+ gtd(check): seam.check → seam.judge
55
+ """
56
+
57
+ Scenario: a test importing a file the pass added is sent back, and an overrule runs the check and sticks
58
+ Given step "seam.naive" writes "src/subtract.ts" with:
59
+ """
60
+ export const subtract = (a: number, b: number) => a - b
61
+ """
62
+ And step "seam.naive" writes "src/subtract.test.ts" with:
63
+ """
64
+ import { subtract } from "./subtract.js"
65
+ it("subtracts", () => expect(subtract(5, 3)).toBe(2))
52
66
  """
53
67
  When the process is driven
54
68
  Then the process rests at "seam.steer"
55
- And the resting step's content contains "acceptance-tests: no test of the naive pass names AC-2"
69
+ And the resting step's content contains "src/subtract.test.ts → src/subtract.ts"
56
70
 
57
71
  Given step "seam.check" changes nothing
58
72
  When gtd lands
@@ -87,27 +101,12 @@ Feature: a naive pass ends only when a test names every criterion and the suite
87
101
  gtd(judge): seam.judge → seam.steer
88
102
  """
89
103
 
90
- Scenario: a test importing a file the pass added is sent back
91
- Given step "seam.naive" writes "src/subtract.ts" with:
92
- """
93
- export const subtract = (a: number, b: number) => a - b
94
- """
95
- And step "seam.naive" writes "src/subtract.test.ts" with:
96
- """
97
- import { subtract } from "./subtract.js"
98
- it("[AC-1] subtracts", () => expect(subtract(5, 3)).toBe(2))
99
- it("[AC-2] still adds", () => {})
100
- """
101
- When the process is driven
102
- Then the process rests at "seam.steer"
103
- And the resting step's content contains "src/subtract.test.ts → src/subtract.ts"
104
-
105
104
  Scenario: a red suite sends the pass back, and it moves on only once green
106
105
  Given step "seam.naive" writes "tests/calc.test.ts" with:
107
106
  """
108
107
  import { add, subtract } from "../src/calc.js"
109
- it("[AC-1] subtracts", () => expect(subtract(5, 3)).toBe(2))
110
- it("[AC-2] still adds", () => expect(add(1, 1)).toBe(2))
108
+ it("subtracts", () => expect(subtract(5, 3)).toBe(2))
109
+ it("still adds", () => expect(add(1, 1)).toBe(2))
111
110
  """
112
111
  When the process is driven
113
112
  Then the process rests at "seam.check"
@@ -118,18 +117,18 @@ Feature: a naive pass ends only when a test names every criterion and the suite
118
117
  Given step "seam.naive" is no longer scripted
119
118
  And step "seam.check" writes ".gtd/FEEDBACK.md" with:
120
119
  """
121
- FAIL tests/calc.test.ts > [AC-1] subtracts
120
+ FAIL tests/calc.test.ts > subtracts
122
121
  """
123
122
  When the process is driven
124
123
  Then the process rests at "seam.naive"
125
124
  And the resting step's content contains "left the suite red"
126
- And ".gtd/FEEDBACK.md" contains "[AC-1] subtracts"
125
+ And ".gtd/FEEDBACK.md" contains "> subtracts"
127
126
 
128
127
  Given step "seam.naive" writes "tests/calc.test.ts" with:
129
128
  """
130
129
  import { add, subtract } from "../src/calc.js"
131
- it("[AC-1] subtracts", () => expect(subtract(5, 3)).toBe(2))
132
- it("[AC-2] still adds", () => expect(add(2, 2)).toBe(4))
130
+ it("subtracts", () => expect(subtract(5, 3)).toBe(2))
131
+ it("still adds", () => expect(add(2, 2)).toBe(4))
133
132
  """
134
133
  And step "seam.check" from now on changes nothing
135
134
  When the process is driven
@@ -3,7 +3,6 @@ import { HEADING, markFenced } from "../shared/fences.js"
3
3
  import { coder, PROTOTYPE, REQUIREMENTS } from "../shared/steps.js"
4
4
  import * as t from "../shared/text.js"
5
5
  import { defaults } from "../shared/vars.js"
6
- import type { Guard } from "../shared/health.js"
7
6
  import { green } from "./green.js"
8
7
  import { criteriaOf, criterionIds, handsOnIds, requireCriteriaFrozen } from "./criteria.js"
9
8
 
@@ -130,7 +129,7 @@ const testing = async (
130
129
  return requireReport(ids, retest)
131
130
  }
132
131
 
133
- const fixing = async (guard?: Guard): Promise<void> => {
132
+ const fixing = async (): Promise<void> => {
134
133
  await scope("fix", () =>
135
134
  t.agentWithSkills("fixing", t.prototypeFixingPrompt(), {
136
135
  label: "Fixing what the hands-on test found",
@@ -145,7 +144,6 @@ const fixing = async (guard?: Guard): Promise<void> => {
145
144
  if (changes().some((c) => c.path === PROTOTYPE))
146
145
  refuse(`gtd land: prototype-fix: leave ${PROTOTYPE} as it is — the next round re-tests from it`)
147
146
  frozen()
148
- guard?.()
149
147
  }
150
148
 
151
149
  /** A person's rest; resolves `true` when they changed something to test again, `false` on a clean overrule. */
@@ -161,10 +159,9 @@ const askPerson = async (name: string, message: string, label: string): Promise<
161
159
  * Use the change by hand: a testing turn reports on every criterion a person
162
160
  * can observe, a fix turn takes each failure, and the change is tested again —
163
161
  * until the report is clean, or `prototypeRounds` fixes are spent and a person
164
- * decides. A change with no such criterion is not tested by hand. `guard`
165
- * holds every fix turn, as it holds the implementation's.
162
+ * decides. A change with no such criterion is not tested by hand.
166
163
  */
167
- export const prototypeTest = async (guard?: Guard): Promise<void> => {
164
+ export const prototypeTest = async (): Promise<void> => {
168
165
  const cap = prototypeRounds()
169
166
  if (cap === 0) return
170
167
  await scope("prototype", async () => {
@@ -185,7 +182,7 @@ export const prototypeTest = async (guard?: Guard): Promise<void> => {
185
182
  } else if (open.length === 0) return
186
183
  else if (fixes < cap && open.some((i) => i.verdict === "fail")) {
187
184
  fixes++
188
- await fixing(guard)
185
+ await fixing()
189
186
  } else {
190
187
  const changed = await askPerson(
191
188
  "open",
@@ -195,7 +192,7 @@ export const prototypeTest = async (guard?: Guard): Promise<void> => {
195
192
  if (!changed) return
196
193
  fixes = 0
197
194
  }
198
- await green(guard)
195
+ await green()
199
196
  }
200
197
  })
201
198
  }
@@ -74,10 +74,6 @@ Feature: a refactor that carried the whole feature still gets a quality lap over
74
74
  """
75
75
  And step "refactor.health.check" changes nothing
76
76
  And step "refactor.closing" runs its script
77
- And judge step "refactor.build.review.ranking" answers:
78
- """
79
- []
80
- """
81
77
  And step "refactor.build.review.carrying" runs its script
82
78
  And step "refactor.build.review.reviewing" writes ".gtd/REVIEW.md" with:
83
79
  """
@@ -100,9 +96,7 @@ Feature: a refactor that carried the whole feature still gets a quality lap over
100
96
 
101
97
  <!-- base: 0000000 -->
102
98
 
103
- ## Walkthrough
104
-
105
- ### calc
99
+ ## calc
106
100
 
107
101
  - [x] ./src/calc.ts#1-2
108
102
  subtract next to add
@@ -77,10 +77,6 @@ Feature: a refactor-first judgment walks one fixed path to the review gate
77
77
  """
78
78
  And step "refactor.health.check" changes nothing
79
79
  And step "refactor.closing" runs its script
80
- And judge step "refactor.build.review.ranking" answers:
81
- """
82
- []
83
- """
84
80
  And step "refactor.build.review.carrying" runs its script
85
81
  And step "refactor.build.review.reviewing" writes ".gtd/REVIEW.md" with:
86
82
  """
@@ -104,9 +100,7 @@ Feature: a refactor-first judgment walks one fixed path to the review gate
104
100
 
105
101
  <!-- base: 0000000 -->
106
102
 
107
- ## Walkthrough
108
-
109
- ### calc
103
+ ## calc
110
104
 
111
105
  - [x] ./src/calc.ts#1-2
112
106
  add built on the shared op
@@ -147,9 +141,7 @@ Feature: a refactor-first judgment walks one fixed path to the review gate
147
141
  gtd(agent): refactor.building → refactor.health.check
148
142
  gtd(check): refactor.health.check → refactor.closing
149
143
  gtd(check): refactor.closing → refactor.build.review.reviewing
150
- gtd(agent): refactor.build.review.reviewing → refactor.build.review.ranking
151
- gtd(judge): refactor.build.review.ranking → refactor.build.review.carrying
152
- gtd(check): refactor.build.review.carrying → refactor.build.review.await-review
144
+ gtd(agent): refactor.build.review.reviewing → refactor.build.review.await-review
153
145
  gtd(human): refactor.build.review.await-review → refactor.build.review.closing
154
146
  gtd(check): refactor.build.review.closing → implement.building
155
147
  gtd(agent): implement.building → implement.health.check
@@ -5,8 +5,9 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
5
5
  On a refactor-first judgment the naive pass is never applied. `seam.note`
6
6
  reads the whole naive diff and writes `.gtd/REFACTOR-NOTE.md`; the refactor
7
7
  lands on its own with the existing suite green; the rebuild re-implements the
8
- change on the refactored base and lands only once it carries the naive pass's
9
- acceptance tests and the suite is green. The note reaches both turns.
8
+ change on the refactored base, is asked to carry over every test file the
9
+ naive pass added or changed, and lands once the suite is green. The note
10
+ reaches both turns.
10
11
 
11
12
  Background:
12
13
  Given the shipped workflows, as gtd install scaffolds them
@@ -18,6 +19,10 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
18
19
  """
19
20
  export const add = (a: number, b: number) => a + b
20
21
  """
22
+ And a file "src/calc.test.ts" with:
23
+ """
24
+ it("adds", () => {})
25
+ """
21
26
  And the working tree is committed as "feat: add calculator"
22
27
  And a file "TODO.md" with:
23
28
  """
@@ -49,7 +54,12 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
49
54
  And step "seam.check" changes nothing
50
55
  And step "seam.naive" writes "src/acceptance.test.ts" with:
51
56
  """
52
- it("[AC-1] subtracts", () => {})
57
+ it("subtracts", () => {})
58
+ """
59
+ And step "seam.naive" writes "src/calc.test.ts" with:
60
+ """
61
+ it("adds", () => {})
62
+ it("subtracts a larger number", () => {})
53
63
  """
54
64
  And step "seam.naive" writes "src/calc.ts" with:
55
65
  """
@@ -88,10 +98,6 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
88
98
  """
89
99
  And step "refactor.health.check" changes nothing
90
100
  And step "refactor.closing" runs its script
91
- And judge step "refactor.build.review.ranking" answers:
92
- """
93
- []
94
- """
95
101
  And step "refactor.build.review.carrying" runs its script
96
102
  And step "refactor.build.review.reviewing" writes ".gtd/REVIEW.md" with:
97
103
  """
@@ -114,9 +120,7 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
114
120
 
115
121
  <!-- base: 0000000 -->
116
122
 
117
- ## Walkthrough
118
-
119
- ### calc
123
+ ## calc
120
124
 
121
125
  - [x] ./src/calc.ts#1-2
122
126
  add built on the shared op
@@ -125,7 +129,8 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
125
129
  And the process is driven
126
130
  Then the process rests at "implement.building"
127
131
  And the resting step's content contains "shared `op(a, b, sign)`"
128
- And the resting step's content contains "acceptance tests for AC-1"
132
+ And the resting step's content contains "Carry over the naive pass's acceptance tests"
133
+ And the resting step's content contains "'src/acceptance.test.ts' 'src/calc.test.ts'"
129
134
 
130
135
  Scenario: a note turn that changes anything but the note is refused
131
136
  Given step "seam.note" writes "src/calc.ts" with:
@@ -159,10 +164,6 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
159
164
  """
160
165
  And step "refactor.health.check" changes nothing
161
166
  And step "refactor.closing" runs its script
162
- And judge step "refactor.build.review.ranking" answers:
163
- """
164
- []
165
- """
166
167
  And step "refactor.build.review.carrying" runs its script
167
168
  And step "refactor.build.review.reviewing" writes ".gtd/REVIEW.md" with:
168
169
  """
@@ -185,9 +186,7 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
185
186
 
186
187
  <!-- base: 0000000 -->
187
188
 
188
- ## Walkthrough
189
-
190
- ### calc
189
+ ## calc
191
190
 
192
191
  - [x] ./src/calc.ts#1-2
193
192
  add built on the shared op
@@ -198,7 +197,7 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
198
197
  And "src/calc.ts" contains "op(a, b, 1)"
199
198
  And "src/calc.ts" does not contain "subtract"
200
199
 
201
- Scenario: the rebuild lands only once it carries the naive pass's acceptance tests, green
200
+ Scenario: the rebuild lands once green, whichever tests it carried
202
201
  Given step "seam.note" writes ".gtd/REFACTOR-NOTE.md" with:
203
202
  """
204
203
  Seam: a shared `op` in src/calc.ts.
@@ -211,10 +210,6 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
211
210
  """
212
211
  And step "refactor.health.check" changes nothing
213
212
  And step "refactor.closing" runs its script
214
- And judge step "refactor.build.review.ranking" answers:
215
- """
216
- []
217
- """
218
213
  And step "refactor.build.review.carrying" runs its script
219
214
  And step "refactor.build.review.reviewing" writes ".gtd/REVIEW.md" with:
220
215
  """
@@ -237,9 +232,7 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
237
232
 
238
233
  <!-- base: 0000000 -->
239
234
 
240
- ## Walkthrough
241
-
242
- ### calc
235
+ ## calc
243
236
 
244
237
  - [x] ./src/calc.ts#1-2
245
238
  add built on the shared op
@@ -254,18 +247,11 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
254
247
  export const add = (a: number, b: number) => op(a, b, 1)
255
248
  export const subtract = (a: number, b: number) => op(a, b, -1)
256
249
  """
257
- Then driving the process is refused with "rebuild-acceptance"
258
-
259
- Given step "implement.building" writes "src/acceptance.test.ts" with:
260
- """
261
- it("[AC-1] subtracts", () => {})
262
- """
263
250
  And step "implement.health.check" changes nothing
264
251
  And step "implement.closing" runs its script
265
252
  When the process is driven
266
253
  Then the process rests at "build.review.reviewing"
267
254
  And "src/calc.ts" contains "op(a, b, -1)"
268
- And "src/acceptance.test.ts" contains "[AC-1]"
269
255
  And ".gtd/REFACTOR-NOTE.md" does not exist
270
256
  And the commit subjects end with:
271
257
  """
@@ -275,9 +261,7 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
275
261
  gtd(agent): refactor.building → refactor.health.check
276
262
  gtd(check): refactor.health.check → refactor.closing
277
263
  gtd(check): refactor.closing → refactor.build.review.reviewing
278
- gtd(agent): refactor.build.review.reviewing → refactor.build.review.ranking
279
- gtd(judge): refactor.build.review.ranking → refactor.build.review.carrying
280
- gtd(check): refactor.build.review.carrying → refactor.build.review.await-review
264
+ gtd(agent): refactor.build.review.reviewing → refactor.build.review.await-review
281
265
  gtd(human): refactor.build.review.await-review → refactor.build.review.closing
282
266
  gtd(check): refactor.build.review.closing → implement.building
283
267
  gtd(agent): implement.building → implement.health.check