@pmelab/gtd 41.0.0 → 42.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +38 -28
- package/dist/chunks/{reserved-Ch4LLrEj.mjs → reserved-D7MNY9QJ.mjs} +58 -14
- package/dist/chunks/{steering-DVILanVf.mjs → steering-oCDdQlpP.mjs} +1 -1
- package/dist/chunks/tail-D2o2h5cc.mjs +246 -0
- package/dist/flows.mjs +11 -1
- package/dist/gtd.bundle.mjs +12 -2
- package/dist/steering.mjs +1 -1
- package/dist/testkit.mjs +15 -3
- package/dist/web/main.js +1 -1
- package/dist/workflow-kit.mjs +1 -1
- package/dist/workflows/cleanup.mjs +2 -2
- package/dist/workflows/feature.mjs +44 -24
- package/dist/workflows/fix.mjs +3 -3
- package/dist/workflows/review.mjs +2 -2
- package/dist/workflows/rollout.mjs +1 -1
- package/dist/workflows.mjs +245 -36
- package/package.json +1 -1
- package/src/flows/scripts.ts +15 -0
- package/src/steering/review.test.ts +2 -20
- package/src/steering/review.ts +2 -1
- package/src/testkit/FlowScripts.test.ts +17 -0
- package/src/testkit/FlowScripts.ts +15 -0
- package/src/testkit/steps.ts +27 -0
- package/src/workflows/feature/coverage.feature +3 -3
- package/src/workflows/feature/fast-path.feature +2 -2
- package/src/workflows/feature/feature.test.ts +2 -37
- package/src/workflows/feature/feature.ts +12 -14
- package/src/workflows/feature/flag-mode.feature +2 -2
- package/src/workflows/feature/lens-review.feature +234 -0
- package/src/workflows/feature/one-step-land.feature +2 -2
- package/src/workflows/feature/quality-unresolved.feature +47 -32
- package/src/workflows/feature/refactor-absorbs.feature +3 -3
- package/src/workflows/feature/refactor-first.feature +5 -5
- package/src/workflows/feature/refactor-rebuild.feature +7 -7
- package/src/workflows/feature/refactor-review.feature +19 -100
- package/src/workflows/feature/refactor.test.ts +12 -27
- package/src/workflows/feature/refactor.ts +0 -1
- package/src/workflows/feature/review-gate.feature +6 -6
- package/src/workflows/feature/review.test.ts +29 -25
- package/src/workflows/feature/review.ts +53 -10
- package/src/workflows/feature/seam-rejection.feature +2 -2
- package/src/workflows/feature/seam.feature +2 -2
- package/src/workflows/feature/seam.test.ts +1 -1
- package/src/workflows/feature/slicing.feature +6 -6
- package/src/workflows/index.ts +1 -0
- package/src/workflows/shared/lenses.test.ts +39 -0
- package/src/workflows/shared/lenses.ts +176 -0
- package/src/workflows/shared/options.ts +1 -0
- package/src/workflows/shared/tail.ts +19 -4
- package/src/workflows/shared/text.test.ts +68 -1
- package/src/workflows/shared/text.ts +126 -13
- package/src/workflows/shared/vars.ts +1 -0
- package/dist/chunks/tail-lY1UmJrU.mjs +0 -112
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest"
|
|
2
|
-
import { runsItsScript, testRepo
|
|
2
|
+
import { runsItsScript, testRepo } from "../../testkit/index.js"
|
|
3
3
|
import { CONFIG_SCAFFOLD } from "../../install/index.js"
|
|
4
4
|
import { reviewDoc } from "../shared/config.fixture.js"
|
|
5
5
|
|
|
@@ -75,10 +75,7 @@ describe("afterTail feedback lap", () => {
|
|
|
75
75
|
`}`,
|
|
76
76
|
].join("\n")
|
|
77
77
|
|
|
78
|
-
const prompts: string[] = []
|
|
79
|
-
|
|
80
78
|
const feedbackLap = async () => {
|
|
81
|
-
prompts.length = 0
|
|
82
79
|
const repo = testRepo({
|
|
83
80
|
workflow: TAIL,
|
|
84
81
|
env: {
|
|
@@ -93,10 +90,7 @@ describe("afterTail feedback lap", () => {
|
|
|
93
90
|
await repo.drive({
|
|
94
91
|
"review-gate.check": () => undefined,
|
|
95
92
|
"build.health.check": () => undefined,
|
|
96
|
-
"build.review.
|
|
97
|
-
prompts.push(beat.content)
|
|
98
|
-
r.write(".gtd/REVIEW.md", review())
|
|
99
|
-
},
|
|
93
|
+
"build.review.composing": (_, r) => r.write(".gtd/REVIEW.md", review()),
|
|
100
94
|
})
|
|
101
95
|
repo.write(".gtd/REVIEW.md", review("also export multiply"))
|
|
102
96
|
await repo.land()
|
|
@@ -137,35 +131,6 @@ describe("afterTail feedback lap", () => {
|
|
|
137
131
|
expect(rest.content).not.toContain("write the change fresh")
|
|
138
132
|
expect(repo.subjects().some((subject) => subject.includes("seam."))).toBe(false)
|
|
139
133
|
})
|
|
140
|
-
|
|
141
|
-
it("the first review says everything since base, the one after feedback only what is new", async () => {
|
|
142
|
-
const repo = await feedbackLap()
|
|
143
|
-
expect(prompts[0]).toContain("it covers everything since the base")
|
|
144
|
-
expect(prompts[0]).not.toContain("only what is new since the previous review")
|
|
145
|
-
const writes: Record<string, () => [string, string]> = {
|
|
146
|
-
"design.triage": () => [
|
|
147
|
-
".gtd/REQUIREMENTS.md",
|
|
148
|
-
"# Requirements\n\n- multiply, designed\n\n## Acceptance Criteria\n\n- AC-1: done\n",
|
|
149
|
-
],
|
|
150
|
-
"implement.building": () => ["src/calc.ts", `${CALC}// again\n`],
|
|
151
|
-
}
|
|
152
|
-
const actors = new Proxy({} as Record<string, Actor>, {
|
|
153
|
-
get: (_, state: string): Actor | undefined =>
|
|
154
|
-
state === "build.review.await-review" || state === "idle"
|
|
155
|
-
? undefined
|
|
156
|
-
: (beat, r) => {
|
|
157
|
-
if (state === "implement.coverage") return '[{"id":"AC-1","answer":"yes","p":0.9}]'
|
|
158
|
-
if (state === "build.review.reviewing") {
|
|
159
|
-
prompts.push(beat.content)
|
|
160
|
-
r.write(".gtd/REVIEW.md", review())
|
|
161
|
-
} else if (writes[state]) r.write(...writes[state]())
|
|
162
|
-
else if (state.endsWith("closing") || state === "re-unwind") r.runScript(beat.content)
|
|
163
|
-
},
|
|
164
|
-
})
|
|
165
|
-
await repo.drive(actors, { maxBeats: 80 })
|
|
166
|
-
expect(prompts[1]).toContain("it covers only what is new since the previous review")
|
|
167
|
-
expect(prompts[1]).not.toContain("everything since the base")
|
|
168
|
-
})
|
|
169
134
|
})
|
|
170
135
|
|
|
171
136
|
describe("an in-flight 28.0.0 naive-pass process", () => {
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
slice,
|
|
10
10
|
start,
|
|
11
11
|
} from "../../flows/index.js"
|
|
12
|
-
import { gate, healthy
|
|
12
|
+
import { gate, healthy } from "../shared/health.js"
|
|
13
13
|
import { flagModeOn, shipped } from "../shared/options.js"
|
|
14
14
|
import { FEEDBACK, fixCheck, QUALITY, REQUIREMENTS } from "../shared/steps.js"
|
|
15
15
|
import { refusePendingHandOff, tail } from "../shared/tail.js"
|
|
@@ -135,8 +135,8 @@ const buildSlice = async (sliceBase: string, build: SliceBuild): Promise<void> =
|
|
|
135
135
|
})
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
//
|
|
139
|
-
//
|
|
138
|
+
// Between slices nothing reviews the lap's leftovers, and the next lap appends to the file.
|
|
139
|
+
// Empty counts as resolved, as the lap reads it.
|
|
140
140
|
const settleQuality = async (): Promise<void> => {
|
|
141
141
|
let rested = false
|
|
142
142
|
while ((read(QUALITY) ?? "").length > 0) {
|
|
@@ -151,15 +151,13 @@ const settleQuality = async (): Promise<void> => {
|
|
|
151
151
|
if (rested) await healthy(() => fixCheck())
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
/** The quality lap, then the human review since `base`. */
|
|
155
|
-
const reviewedTail = (base: string, lensBase: string
|
|
156
|
-
tail(
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
{ green: true, lensBase },
|
|
162
|
-
)
|
|
154
|
+
/** The triaged quality lap, then the human review since `base`. */
|
|
155
|
+
const reviewedTail = (base: string, lensBase: string): Promise<ReviewOutcome> =>
|
|
156
|
+
tail((escalations, report) => review(base, escalations, { report }), {
|
|
157
|
+
green: true,
|
|
158
|
+
lensBase,
|
|
159
|
+
triage: true,
|
|
160
|
+
})
|
|
163
161
|
|
|
164
162
|
// seam.naive / seam.judge never run on a feedback lap: its design → implement is built unjudged
|
|
165
163
|
// and unrefactored, held to every criterion's coverage since the process start.
|
|
@@ -181,7 +179,7 @@ const featureFeedback = async (
|
|
|
181
179
|
})
|
|
182
180
|
const tier = riskTierOn() ? recordRisk() : undefined
|
|
183
181
|
closed = await implementing({ tier, amend: true })
|
|
184
|
-
outcome = await reviewedTail(outcome.base, lensBase
|
|
182
|
+
outcome = await reviewedTail(outcome.base, lensBase)
|
|
185
183
|
}
|
|
186
184
|
}
|
|
187
185
|
|
|
@@ -201,7 +199,7 @@ export const afterTail = async (first: ReviewOutcome): Promise<void> => {
|
|
|
201
199
|
await design(outcome.base)
|
|
202
200
|
const tier = riskTierOn() ? recordRisk() : undefined
|
|
203
201
|
await implement({ tier, amend: true })
|
|
204
|
-
outcome = await buildTail(outcome.base, { green: true
|
|
202
|
+
outcome = await buildTail(outcome.base, { green: true })
|
|
205
203
|
}
|
|
206
204
|
}
|
|
207
205
|
|
|
@@ -67,7 +67,7 @@ Feature: flag mode off lands the naive pass with no release flag, seam judge or
|
|
|
67
67
|
"""
|
|
68
68
|
And step "build.quality.correctness.reviewing" changes nothing
|
|
69
69
|
When the process is driven
|
|
70
|
-
Then the process rests at "build.review.
|
|
70
|
+
Then the process rests at "build.review.composing"
|
|
71
71
|
And "src/calc.ts" contains "subtract"
|
|
72
72
|
And "src/calc.test.ts" contains "[AC-1] subtracts"
|
|
73
73
|
And the commit subjects end with:
|
|
@@ -85,5 +85,5 @@ Feature: flag mode off lands the naive pass with no release flag, seam judge or
|
|
|
85
85
|
gtd(check): implement.health.check → implement.coverage
|
|
86
86
|
gtd(judge): implement.coverage → implement.closing
|
|
87
87
|
gtd(check): implement.closing → build.quality.correctness.reviewing
|
|
88
|
-
gtd(agent): build.quality.correctness.reviewing → build.review.
|
|
88
|
+
gtd(agent): build.quality.correctness.reviewing → build.review.composing
|
|
89
89
|
"""
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
@inmem
|
|
2
|
+
Feature: the quality lenses are the only agentic review
|
|
3
|
+
|
|
4
|
+
A judge classifies each `## ` finding the lenses wrote to `.gtd/QUALITY.md`:
|
|
5
|
+
a mechanical one is fixed by the fixer, noise is dropped with its `p` kept in
|
|
6
|
+
a trailer, and a design one becomes a note in `.gtd/REVIEW.md`. gtd writes
|
|
7
|
+
that file itself — no reviewer turn runs — and lists, without tick boxes,
|
|
8
|
+
what was fixed automatically and what was dropped as noise.
|
|
9
|
+
|
|
10
|
+
Background:
|
|
11
|
+
Given the shipped workflows, as gtd install scaffolds them
|
|
12
|
+
And an environment variable "GTD_QUALITYREVIEWS" set to "correctness"
|
|
13
|
+
And an environment variable "GTD_FLAGMODE" set to "false"
|
|
14
|
+
And a file "src/calc.ts" with:
|
|
15
|
+
"""
|
|
16
|
+
export const add = (a: number, b: number) => a + b
|
|
17
|
+
"""
|
|
18
|
+
And the working tree is committed as "feat: add calculator"
|
|
19
|
+
And a file "TODO.md" with:
|
|
20
|
+
"""
|
|
21
|
+
# Add subtract
|
|
22
|
+
|
|
23
|
+
subtract(a, b) returns the difference.
|
|
24
|
+
"""
|
|
25
|
+
And step "unwind" changes nothing
|
|
26
|
+
And step "start-gate.check" changes nothing
|
|
27
|
+
And step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
|
|
28
|
+
"""
|
|
29
|
+
# Requirements
|
|
30
|
+
|
|
31
|
+
## Concerns
|
|
32
|
+
|
|
33
|
+
### Subtract
|
|
34
|
+
|
|
35
|
+
- `subtract(a, b)` returns `a - b`.
|
|
36
|
+
|
|
37
|
+
## Acceptance Criteria
|
|
38
|
+
|
|
39
|
+
- AC-1: subtract(a, b) returns a - b.
|
|
40
|
+
"""
|
|
41
|
+
And step "design.gate.answer" changes nothing
|
|
42
|
+
And step "seam.naive" writes "src/calc.test.ts" with:
|
|
43
|
+
"""
|
|
44
|
+
it("[AC-1] subtracts", () => {})
|
|
45
|
+
"""
|
|
46
|
+
And step "seam.naive" writes "src/calc.ts" with:
|
|
47
|
+
"""
|
|
48
|
+
export const add = (a: number, b: number) => a + b
|
|
49
|
+
export const subtract = (a: number, b: number) => a - b
|
|
50
|
+
"""
|
|
51
|
+
And step "seam.check" changes nothing
|
|
52
|
+
And step "implement.applying" runs its script
|
|
53
|
+
And step "implement.health.check" changes nothing
|
|
54
|
+
And step "implement.closing" runs its script
|
|
55
|
+
And judge step "implement.coverage" answers:
|
|
56
|
+
"""
|
|
57
|
+
[{"id":"AC-1","answer":"yes","p":0.9}]
|
|
58
|
+
"""
|
|
59
|
+
And step "build.quality.correctness.reviewing" writes ".gtd/QUALITY.md" with:
|
|
60
|
+
"""
|
|
61
|
+
# Quality
|
|
62
|
+
|
|
63
|
+
## subtract has no negative test
|
|
64
|
+
|
|
65
|
+
Add a test subtracting a larger number.
|
|
66
|
+
|
|
67
|
+
## add could be a method
|
|
68
|
+
|
|
69
|
+
A class would read better.
|
|
70
|
+
|
|
71
|
+
## AC-1 ignores floating point
|
|
72
|
+
|
|
73
|
+
Should subtract round? The criterion does not say.
|
|
74
|
+
"""
|
|
75
|
+
And step "build.quality.sorting" runs its script
|
|
76
|
+
And step "build.review.composing" runs its script
|
|
77
|
+
|
|
78
|
+
Scenario: a mechanical finding is fixed and listed, noise dropped and listed, a design one noted
|
|
79
|
+
Given judge step "build.quality.triage" answers:
|
|
80
|
+
"""
|
|
81
|
+
[{"id":"Q1","answer":"mechanical","p":0.9},{"id":"Q2","answer":"noise","p":0.85},{"id":"Q3","answer":"design","p":0.8}]
|
|
82
|
+
"""
|
|
83
|
+
And step "build.fix.quality.fixing" writes "src/calc.test.ts" with:
|
|
84
|
+
"""
|
|
85
|
+
it("[AC-1] subtracts", () => {})
|
|
86
|
+
it("subtracts a larger number", () => {})
|
|
87
|
+
"""
|
|
88
|
+
And step "build.fix.quality.fixing" deletes ".gtd/QUALITY.md"
|
|
89
|
+
And step "build.health.check" changes nothing
|
|
90
|
+
When the process is driven
|
|
91
|
+
Then the process rests at "build.review.await-review"
|
|
92
|
+
And ".gtd/QUALITY.md" does not exist
|
|
93
|
+
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"
|
|
94
|
+
And ".gtd/REVIEW.md" contains:
|
|
95
|
+
"""
|
|
96
|
+
## AC-1 ignores floating point
|
|
97
|
+
|
|
98
|
+
Should subtract round? The criterion does not say.
|
|
99
|
+
|
|
100
|
+
## Fixed automatically
|
|
101
|
+
|
|
102
|
+
- subtract has no negative test (
|
|
103
|
+
"""
|
|
104
|
+
And ".gtd/REVIEW.md" contains the short hash of the commit "gtd(agent): build.fix.quality.fixing → build.health.check"
|
|
105
|
+
And ".gtd/REVIEW.md" contains:
|
|
106
|
+
"""
|
|
107
|
+
## Dropped as noise
|
|
108
|
+
|
|
109
|
+
- add could be a method (p=0.85)
|
|
110
|
+
"""
|
|
111
|
+
And ".gtd/REVIEW.md" does not contain "[ ]"
|
|
112
|
+
And the commit subjects end with:
|
|
113
|
+
"""
|
|
114
|
+
gtd(check): implement.closing → build.quality.correctness.reviewing
|
|
115
|
+
gtd(agent): build.quality.correctness.reviewing → build.quality.triage
|
|
116
|
+
gtd(judge): build.quality.triage → build.quality.sorting
|
|
117
|
+
gtd(check): build.quality.sorting → build.fix.quality.fixing
|
|
118
|
+
gtd(agent): build.fix.quality.fixing → build.health.check
|
|
119
|
+
gtd(check): build.health.check → build.review.composing
|
|
120
|
+
gtd(check): build.review.composing → build.review.await-review
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
|
+
Scenario: an unsure verdict makes a finding a note, never a fix or a drop
|
|
124
|
+
Given judge step "build.quality.triage" answers:
|
|
125
|
+
"""
|
|
126
|
+
[{"id":"Q1","answer":"mechanical","p":0.5},{"id":"Q2","answer":"noise","p":0.6}]
|
|
127
|
+
"""
|
|
128
|
+
When the process is driven
|
|
129
|
+
Then the process rests at "build.review.await-review"
|
|
130
|
+
And ".gtd/REVIEW.md" contains "## subtract has no negative test"
|
|
131
|
+
And ".gtd/REVIEW.md" contains "## add could be a method"
|
|
132
|
+
And ".gtd/REVIEW.md" contains "## AC-1 ignores floating point"
|
|
133
|
+
And ".gtd/REVIEW.md" does not contain "Fixed automatically"
|
|
134
|
+
And no commit body contains "Gtd-Mark: noise="
|
|
135
|
+
And the commit subjects end with:
|
|
136
|
+
"""
|
|
137
|
+
gtd(judge): build.quality.triage → build.quality.sorting
|
|
138
|
+
gtd(check): build.quality.sorting → build.review.composing
|
|
139
|
+
gtd(check): build.review.composing → build.review.await-review
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
Scenario: a mechanical finding the fix cap leaves becomes a note
|
|
143
|
+
Given judge step "build.quality.triage" answers:
|
|
144
|
+
"""
|
|
145
|
+
[{"id":"Q1","answer":"mechanical","p":0.9},{"id":"Q2","answer":"mechanical","p":0.9},{"id":"Q3","answer":"mechanical","p":0.9}]
|
|
146
|
+
"""
|
|
147
|
+
And step "build.fix.quality.fixing" writes ".gtd/QUALITY.md" with:
|
|
148
|
+
"""
|
|
149
|
+
# Quality
|
|
150
|
+
|
|
151
|
+
## add could be a method
|
|
152
|
+
|
|
153
|
+
A class would read better.
|
|
154
|
+
"""
|
|
155
|
+
And step "build.health.check" changes nothing
|
|
156
|
+
When the process is driven
|
|
157
|
+
Then the process rests at "build.review.await-review"
|
|
158
|
+
And ".gtd/QUALITY.md" does not exist
|
|
159
|
+
And ".gtd/REVIEW.md" contains:
|
|
160
|
+
"""
|
|
161
|
+
## add could be a method
|
|
162
|
+
|
|
163
|
+
_The fixer left this unresolved._
|
|
164
|
+
|
|
165
|
+
A class would read better.
|
|
166
|
+
"""
|
|
167
|
+
And ".gtd/REVIEW.md" contains "- subtract has no negative test ("
|
|
168
|
+
And ".gtd/REVIEW.md" contains "- AC-1 ignores floating point ("
|
|
169
|
+
And the commit subjects end with:
|
|
170
|
+
"""
|
|
171
|
+
gtd(judge): build.quality.triage → build.fix.quality.fixing
|
|
172
|
+
gtd(agent): build.fix.quality.fixing
|
|
173
|
+
gtd(agent): build.fix.quality.fixing
|
|
174
|
+
gtd(agent): build.fix.quality.fixing → build.health.check
|
|
175
|
+
gtd(check): build.health.check → build.review.composing
|
|
176
|
+
gtd(check): build.review.composing → build.review.await-review
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
Scenario: a fixer that renames a chunk it leaves counts nothing fixed
|
|
180
|
+
Given judge step "build.quality.triage" answers:
|
|
181
|
+
"""
|
|
182
|
+
[{"id":"Q1","answer":"mechanical","p":0.9},{"id":"Q2","answer":"mechanical","p":0.9},{"id":"Q3","answer":"mechanical","p":0.9}]
|
|
183
|
+
"""
|
|
184
|
+
And step "build.fix.quality.fixing" writes ".gtd/QUALITY.md" with:
|
|
185
|
+
"""
|
|
186
|
+
# Quality
|
|
187
|
+
|
|
188
|
+
## null check in parse()
|
|
189
|
+
|
|
190
|
+
Still open.
|
|
191
|
+
"""
|
|
192
|
+
And step "build.health.check" changes nothing
|
|
193
|
+
When the process is driven
|
|
194
|
+
Then the process rests at "build.review.await-review"
|
|
195
|
+
And ".gtd/REVIEW.md" contains "## null check in parse()"
|
|
196
|
+
And ".gtd/REVIEW.md" contains "## subtract has no negative test"
|
|
197
|
+
And ".gtd/REVIEW.md" contains "check whether it was fixed"
|
|
198
|
+
And ".gtd/REVIEW.md" does not contain "Fixed automatically"
|
|
199
|
+
|
|
200
|
+
Scenario: prose the fixer leaves outside every chunk does not hide its fixes
|
|
201
|
+
Given judge step "build.quality.triage" answers:
|
|
202
|
+
"""
|
|
203
|
+
[{"id":"Q1","answer":"mechanical","p":0.9},{"id":"Q2","answer":"mechanical","p":0.9},{"id":"Q3","answer":"mechanical","p":0.9}]
|
|
204
|
+
"""
|
|
205
|
+
And step "build.fix.quality.fixing" writes ".gtd/QUALITY.md" with:
|
|
206
|
+
"""
|
|
207
|
+
# Quality
|
|
208
|
+
|
|
209
|
+
All fixed.
|
|
210
|
+
"""
|
|
211
|
+
And step "build.health.check" changes nothing
|
|
212
|
+
When the process is driven
|
|
213
|
+
Then the process rests at "build.review.await-review"
|
|
214
|
+
And ".gtd/REVIEW.md" contains "- subtract has no negative test ("
|
|
215
|
+
And ".gtd/REVIEW.md" does not contain "check whether it was fixed"
|
|
216
|
+
|
|
217
|
+
Scenario: signing off a composed review ends the process
|
|
218
|
+
Given judge step "build.quality.triage" answers:
|
|
219
|
+
"""
|
|
220
|
+
[{"id":"Q1","answer":"noise","p":0.9},{"id":"Q2","answer":"noise","p":0.9},{"id":"Q3","answer":"noise","p":0.9}]
|
|
221
|
+
"""
|
|
222
|
+
And step "build.review.closing" runs its script
|
|
223
|
+
When the process is driven
|
|
224
|
+
Then the process rests at "build.review.await-review"
|
|
225
|
+
When gtd lands
|
|
226
|
+
And the process is driven
|
|
227
|
+
Then the process rests at "idle"
|
|
228
|
+
And ".gtd/REVIEW.md" does not exist
|
|
229
|
+
And the commit subjects end with:
|
|
230
|
+
"""
|
|
231
|
+
gtd(check): build.review.composing → build.review.await-review
|
|
232
|
+
gtd(human): build.review.await-review → build.review.closing
|
|
233
|
+
gtd(check): build.review.closing → idle
|
|
234
|
+
"""
|
|
@@ -64,7 +64,7 @@ Feature: a naive pass the judge rules land is itself the implementation
|
|
|
64
64
|
|
|
65
65
|
Scenario: a land judgment applies the naive pass and runs from idle to the review gate with no rebuild
|
|
66
66
|
When the process is driven
|
|
67
|
-
Then the process rests at "build.review.
|
|
67
|
+
Then the process rests at "build.review.composing"
|
|
68
68
|
And "src/greeting.ts" contains "Hello, world"
|
|
69
69
|
And "src/acceptance.test.ts" contains "[AC-1] holds"
|
|
70
70
|
And the commit subjects end with:
|
|
@@ -81,7 +81,7 @@ Feature: a naive pass the judge rules land is itself the implementation
|
|
|
81
81
|
gtd(check): implement.health.check → implement.coverage
|
|
82
82
|
gtd(judge): implement.coverage → implement.closing
|
|
83
83
|
gtd(check): implement.closing → build.quality.correctness.reviewing
|
|
84
|
-
gtd(agent): build.quality.correctness.reviewing → build.review.
|
|
84
|
+
gtd(agent): build.quality.correctness.reviewing → build.review.composing
|
|
85
85
|
"""
|
|
86
86
|
And the commit "gtd(human): idle → unwind" has a body containing "Gtd-Var: flag_risk_tier=0"
|
|
87
87
|
And the commit "gtd(agent): seam.naive → seam.check" has a body containing "Gtd-Kept:"
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
@inmem
|
|
2
|
-
Feature: quality findings left unresolved
|
|
2
|
+
Feature: quality findings left unresolved between slices hold the next slice back
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
Between slices no review reads the quality lap's leftovers, so when the fix
|
|
5
|
+
cap leaves `.gtd/QUALITY.md` behind the process rests for a person before
|
|
6
|
+
the next slice. The last slice's leftovers become review notes instead (see
|
|
7
|
+
`lens-review.feature`).
|
|
7
8
|
|
|
8
9
|
Background:
|
|
9
10
|
Given the shipped workflows, as gtd install scaffolds them
|
|
10
11
|
And an environment variable "GTD_QUALITYREVIEWS" set to "correctness"
|
|
11
12
|
And an environment variable "GTD_FLAGMODE" set to "false"
|
|
13
|
+
And an environment variable "GTD_SLICEMAXCRITERIA" set to "1"
|
|
12
14
|
And a file "src/calc.ts" with:
|
|
13
15
|
"""
|
|
14
16
|
export const add = (a: number, b: number) => a + b
|
|
@@ -16,9 +18,9 @@ Feature: quality findings left unresolved hold a feature process short of its re
|
|
|
16
18
|
And the working tree is committed as "feat: add calculator"
|
|
17
19
|
And a file "TODO.md" with:
|
|
18
20
|
"""
|
|
19
|
-
#
|
|
21
|
+
# More arithmetic
|
|
20
22
|
|
|
21
|
-
subtract
|
|
23
|
+
subtract and multiply.
|
|
22
24
|
"""
|
|
23
25
|
And step "unwind" changes nothing
|
|
24
26
|
And step "start-gate.check" changes nothing
|
|
@@ -26,41 +28,53 @@ Feature: quality findings left unresolved hold a feature process short of its re
|
|
|
26
28
|
"""
|
|
27
29
|
# Requirements
|
|
28
30
|
|
|
29
|
-
## Concerns
|
|
30
|
-
|
|
31
|
-
### Subtract
|
|
32
|
-
|
|
33
|
-
- `subtract(a, b)` returns `a - b`.
|
|
34
|
-
|
|
35
31
|
## Acceptance Criteria
|
|
36
32
|
|
|
37
33
|
- AC-1: subtract(a, b) returns a - b.
|
|
34
|
+
- AC-2: multiply(a, b) returns a * b.
|
|
38
35
|
"""
|
|
39
36
|
And step "design.gate.answer" changes nothing
|
|
40
|
-
And step "
|
|
37
|
+
And step "design.slicing" writes ".gtd/SLICES.md" with:
|
|
38
|
+
"""
|
|
39
|
+
# Slices
|
|
40
|
+
|
|
41
|
+
## Subtract
|
|
42
|
+
|
|
43
|
+
- AC-1
|
|
44
|
+
|
|
45
|
+
## Multiply
|
|
46
|
+
|
|
47
|
+
- AC-2
|
|
48
|
+
"""
|
|
49
|
+
And step "seam.naive", when prompted with "This slice builds AC-1 only", writes "src/sub.test.ts" with:
|
|
41
50
|
"""
|
|
42
51
|
it("[AC-1] subtracts", () => {})
|
|
43
52
|
"""
|
|
44
|
-
And step "seam.naive" writes "src/
|
|
53
|
+
And step "seam.naive", when prompted with "This slice builds AC-2 only", writes "src/mul.test.ts" with:
|
|
45
54
|
"""
|
|
46
|
-
|
|
47
|
-
export const subtract = (a: number, b: number) => a - b
|
|
55
|
+
it("[AC-2] multiplies", () => {})
|
|
48
56
|
"""
|
|
49
57
|
And step "seam.check" changes nothing
|
|
50
58
|
And step "implement.applying" runs its script
|
|
51
59
|
And step "implement.health.check" changes nothing
|
|
52
60
|
And step "implement.closing" runs its script
|
|
53
|
-
And judge step "implement.coverage" answers:
|
|
61
|
+
And judge step "implement.coverage", when its questions contain "AC-1", answers:
|
|
54
62
|
"""
|
|
55
63
|
[{"id":"AC-1","answer":"yes","p":0.9}]
|
|
56
64
|
"""
|
|
65
|
+
And judge step "implement.coverage", when its questions contain "AC-2", answers:
|
|
66
|
+
"""
|
|
67
|
+
[{"id":"AC-2","answer":"yes","p":0.9}]
|
|
68
|
+
"""
|
|
57
69
|
|
|
58
|
-
Scenario: findings the fix cap left
|
|
70
|
+
Scenario: findings the fix cap left after a slice rest at build.quality-unresolved
|
|
59
71
|
Given step "build.quality.correctness.reviewing" writes ".gtd/QUALITY.md" with:
|
|
60
72
|
"""
|
|
61
73
|
# Quality
|
|
62
74
|
|
|
63
|
-
|
|
75
|
+
## subtract has no negative test
|
|
76
|
+
|
|
77
|
+
Add a test subtracting a larger number.
|
|
64
78
|
"""
|
|
65
79
|
And step "build.fix.quality.fixing" from now on changes nothing
|
|
66
80
|
And step "build.health.describe" writes ".gtd/ESCALATION.md" with:
|
|
@@ -74,33 +88,34 @@ Feature: quality findings left unresolved hold a feature process short of its re
|
|
|
74
88
|
Given step "build.fix" writes "src/calc.ts" with:
|
|
75
89
|
"""
|
|
76
90
|
export const add = (a: number, b: number) => a + b
|
|
77
|
-
export const subtract = (a: number, b: number) => a - b
|
|
78
91
|
// checked
|
|
79
92
|
"""
|
|
80
93
|
And step "build.health.check" changes nothing
|
|
81
94
|
When gtd lands
|
|
82
95
|
And the process is driven
|
|
83
96
|
Then the process rests at "build.quality-unresolved"
|
|
84
|
-
And ".gtd/QUALITY.md" contains "subtract has no test"
|
|
97
|
+
And ".gtd/QUALITY.md" contains "subtract has no negative test"
|
|
85
98
|
|
|
86
99
|
When gtd lands
|
|
87
100
|
And the process is driven
|
|
88
101
|
Then the process rests at "build.quality-unresolved"
|
|
89
102
|
|
|
90
|
-
Given
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
export const subtract = (a: number, b: number) => a - b
|
|
94
|
-
// checked by hand
|
|
95
|
-
"""
|
|
96
|
-
And the file ".gtd/QUALITY.md" is deleted
|
|
97
|
-
And step "build.health.check" changes nothing
|
|
103
|
+
Given the file ".gtd/QUALITY.md" is deleted
|
|
104
|
+
And step "build.quality.correctness.reviewing" from now on changes nothing
|
|
105
|
+
And step "build.review.composing" runs its script
|
|
98
106
|
When gtd lands
|
|
99
107
|
And the process is driven
|
|
100
|
-
Then the process rests at "build.review.
|
|
108
|
+
Then the process rests at "build.review.await-review"
|
|
101
109
|
And the commit subjects end with:
|
|
102
110
|
"""
|
|
103
|
-
gtd(check): build.health.check → build.quality-unresolved
|
|
104
111
|
gtd(human): build.quality-unresolved → build.health.check
|
|
105
|
-
gtd(check): build.health.check →
|
|
112
|
+
gtd(check): build.health.check → seam.naive
|
|
113
|
+
gtd(agent): seam.naive → seam.check
|
|
114
|
+
gtd(check): seam.check → implement.applying
|
|
115
|
+
gtd(check): implement.applying → implement.health.check
|
|
116
|
+
gtd(check): implement.health.check → implement.coverage
|
|
117
|
+
gtd(judge): implement.coverage → implement.closing
|
|
118
|
+
gtd(check): implement.closing → build.quality.correctness.reviewing
|
|
119
|
+
gtd(agent): build.quality.correctness.reviewing → build.review.composing
|
|
120
|
+
gtd(check): build.review.composing → build.review.await-review
|
|
106
121
|
"""
|
|
@@ -69,7 +69,7 @@ Feature: a refactor that carried the whole feature still gets a quality lap over
|
|
|
69
69
|
"""
|
|
70
70
|
And step "refactor.health.check" changes nothing
|
|
71
71
|
And step "refactor.closing" runs its script
|
|
72
|
-
And step "refactor.build.review.
|
|
72
|
+
And step "refactor.build.review.composing" writes ".gtd/REVIEW.md" with:
|
|
73
73
|
"""
|
|
74
74
|
# Review: abc1234
|
|
75
75
|
|
|
@@ -113,7 +113,7 @@ Feature: a refactor that carried the whole feature still gets a quality lap over
|
|
|
113
113
|
|
|
114
114
|
Given step "build.quality.correctness.reviewing" changes nothing
|
|
115
115
|
When the process is driven
|
|
116
|
-
Then the process rests at "build.review.
|
|
116
|
+
Then the process rests at "build.review.composing"
|
|
117
117
|
And "src/calc.ts" contains "subtract"
|
|
118
118
|
And the commit subjects end with:
|
|
119
119
|
"""
|
|
@@ -123,7 +123,7 @@ Feature: a refactor that carried the whole feature still gets a quality lap over
|
|
|
123
123
|
gtd(check): implement.health.check → implement.coverage
|
|
124
124
|
gtd(judge): implement.coverage → implement.closing
|
|
125
125
|
gtd(check): implement.closing → build.quality.correctness.reviewing
|
|
126
|
-
gtd(agent): build.quality.correctness.reviewing → build.review.
|
|
126
|
+
gtd(agent): build.quality.correctness.reviewing → build.review.composing
|
|
127
127
|
"""
|
|
128
128
|
And the output lines of gtd "slices" start with:
|
|
129
129
|
"""
|
|
@@ -72,7 +72,7 @@ Feature: a refactor-first judgment walks one fixed path to the review gate
|
|
|
72
72
|
"""
|
|
73
73
|
And step "refactor.health.check" changes nothing
|
|
74
74
|
And step "refactor.closing" runs its script
|
|
75
|
-
And step "refactor.build.review.
|
|
75
|
+
And step "refactor.build.review.composing" writes ".gtd/REVIEW.md" with:
|
|
76
76
|
"""
|
|
77
77
|
# Review: abc1234
|
|
78
78
|
|
|
@@ -121,7 +121,7 @@ Feature: a refactor-first judgment walks one fixed path to the review gate
|
|
|
121
121
|
[{"id":"AC-1","answer":"yes","p":0.9}]
|
|
122
122
|
"""
|
|
123
123
|
When the process is driven
|
|
124
|
-
Then the process rests at "build.review.
|
|
124
|
+
Then the process rests at "build.review.composing"
|
|
125
125
|
And "src/calc.ts" contains "op(a, b, 1)"
|
|
126
126
|
And "src/calc.ts" contains "subtract"
|
|
127
127
|
And the commit subjects end with:
|
|
@@ -138,14 +138,14 @@ Feature: a refactor-first judgment walks one fixed path to the review gate
|
|
|
138
138
|
gtd(check): refactor.deriving → refactor.building
|
|
139
139
|
gtd(agent): refactor.building → refactor.health.check
|
|
140
140
|
gtd(check): refactor.health.check → refactor.closing
|
|
141
|
-
gtd(check): refactor.closing → refactor.build.review.
|
|
142
|
-
gtd(
|
|
141
|
+
gtd(check): refactor.closing → refactor.build.review.composing
|
|
142
|
+
gtd(check): refactor.build.review.composing → refactor.build.review.await-review
|
|
143
143
|
gtd(human): refactor.build.review.await-review → refactor.build.review.closing
|
|
144
144
|
gtd(check): refactor.build.review.closing → implement.building
|
|
145
145
|
gtd(agent): implement.building → implement.health.check
|
|
146
146
|
gtd(check): implement.health.check → implement.coverage
|
|
147
147
|
gtd(judge): implement.coverage → implement.closing
|
|
148
|
-
gtd(check): implement.closing → build.review.
|
|
148
|
+
gtd(check): implement.closing → build.review.composing
|
|
149
149
|
"""
|
|
150
150
|
And the commit "gtd(human): idle → unwind" has a body containing "Gtd-Var: flag_risk_tier=0"
|
|
151
151
|
And the commit "gtd(agent): seam.naive → seam.check" has a body containing "Gtd-Kept:"
|
|
@@ -83,7 +83,7 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
|
|
|
83
83
|
"""
|
|
84
84
|
And step "refactor.health.check" changes nothing
|
|
85
85
|
And step "refactor.closing" runs its script
|
|
86
|
-
And step "refactor.build.review.
|
|
86
|
+
And step "refactor.build.review.composing" writes ".gtd/REVIEW.md" with:
|
|
87
87
|
"""
|
|
88
88
|
# Review: abc1234
|
|
89
89
|
|
|
@@ -147,7 +147,7 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
|
|
|
147
147
|
"""
|
|
148
148
|
And step "refactor.health.check" changes nothing
|
|
149
149
|
And step "refactor.closing" runs its script
|
|
150
|
-
And step "refactor.build.review.
|
|
150
|
+
And step "refactor.build.review.composing" writes ".gtd/REVIEW.md" with:
|
|
151
151
|
"""
|
|
152
152
|
# Review: abc1234
|
|
153
153
|
|
|
@@ -193,7 +193,7 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
|
|
|
193
193
|
"""
|
|
194
194
|
And step "refactor.health.check" changes nothing
|
|
195
195
|
And step "refactor.closing" runs its script
|
|
196
|
-
And step "refactor.build.review.
|
|
196
|
+
And step "refactor.build.review.composing" writes ".gtd/REVIEW.md" with:
|
|
197
197
|
"""
|
|
198
198
|
# Review: abc1234
|
|
199
199
|
|
|
@@ -242,7 +242,7 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
|
|
|
242
242
|
[{"id":"AC-1","answer":"yes","p":0.9}]
|
|
243
243
|
"""
|
|
244
244
|
When the process is driven
|
|
245
|
-
Then the process rests at "build.review.
|
|
245
|
+
Then the process rests at "build.review.composing"
|
|
246
246
|
And "src/calc.ts" contains "op(a, b, -1)"
|
|
247
247
|
And "src/acceptance.test.ts" contains "[AC-1]"
|
|
248
248
|
And ".gtd/REFACTOR-NOTE.md" does not exist
|
|
@@ -253,14 +253,14 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
|
|
|
253
253
|
gtd(check): refactor.deriving → refactor.building
|
|
254
254
|
gtd(agent): refactor.building → refactor.health.check
|
|
255
255
|
gtd(check): refactor.health.check → refactor.closing
|
|
256
|
-
gtd(check): refactor.closing → refactor.build.review.
|
|
257
|
-
gtd(
|
|
256
|
+
gtd(check): refactor.closing → refactor.build.review.composing
|
|
257
|
+
gtd(check): refactor.build.review.composing → refactor.build.review.await-review
|
|
258
258
|
gtd(human): refactor.build.review.await-review → refactor.build.review.closing
|
|
259
259
|
gtd(check): refactor.build.review.closing → implement.building
|
|
260
260
|
gtd(agent): implement.building → implement.health.check
|
|
261
261
|
gtd(check): implement.health.check → implement.coverage
|
|
262
262
|
gtd(judge): implement.coverage → implement.closing
|
|
263
|
-
gtd(check): implement.closing → build.review.
|
|
263
|
+
gtd(check): implement.closing → build.review.composing
|
|
264
264
|
"""
|
|
265
265
|
And the output lines of gtd "slices" start with:
|
|
266
266
|
"""
|