@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.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +41 -38
- package/dist/chunks/{reserved-CUkk9XgL.mjs → reserved-D0MKVFFa.mjs} +28 -34
- package/dist/chunks/{review-BaCXlIT2.mjs → review-ZzUQH1KZ.mjs} +11 -9
- package/dist/chunks/{steering-DtUVUz9l.mjs → steering-CLhu8C7q.mjs} +262 -52
- package/dist/chunks/{tail-CX6Pdsql.mjs → tail-I1-vVq0P.mjs} +1 -1
- package/dist/gtd.bundle.mjs +198 -43
- package/dist/steering.mjs +2 -2
- package/dist/testkit.mjs +1 -1
- package/dist/web/main.css +1 -1
- package/dist/web/main.js +510 -147
- package/dist/workflow-kit.mjs +1 -1
- package/dist/workflows/cleanup.mjs +2 -2
- package/dist/workflows/feature.mjs +181 -222
- package/dist/workflows/fix.mjs +3 -3
- package/dist/workflows/review.mjs +3 -3
- package/dist/workflows/rollout.mjs +1 -1
- package/dist/workflows.mjs +478 -313
- package/package.json +1 -1
- package/src/steering/FORMATS.md +4 -1
- package/src/steering/SteeringFormat.ts +7 -1
- package/src/steering/contract.test.ts +2 -1
- package/src/steering/fixtures/review/sectioned.md +31 -0
- package/src/steering/fixtures/review/sectioned.read.json +119 -0
- package/src/steering/index.ts +4 -0
- package/src/steering/qa.ts +1 -1
- package/src/steering/review.test.ts +270 -4
- package/src/steering/review.ts +328 -69
- package/src/workflows/feature/criteria.test.ts +39 -1
- package/src/workflows/feature/criteria.ts +21 -7
- package/src/workflows/feature/fast-path.feature +1 -6
- package/src/workflows/feature/feature.ts +1 -2
- package/src/workflows/feature/flag-mode.feature +1 -6
- package/src/workflows/feature/green.ts +22 -0
- package/src/workflows/feature/hands-on-skip.feature +344 -0
- package/src/workflows/feature/lens-models.feature +0 -4
- package/src/workflows/feature/lens-review.feature +6 -8
- package/src/workflows/feature/one-step-land.feature +1 -6
- package/src/workflows/feature/prototype-rounds.feature +1 -1
- package/src/workflows/feature/prototype.feature +10 -9
- package/src/workflows/feature/prototype.ts +48 -17
- package/src/workflows/feature/refactor-absorbs.feature +3 -8
- package/src/workflows/feature/refactor-first.feature +3 -8
- package/src/workflows/feature/refactor-rebuild.feature +7 -12
- package/src/workflows/feature/refactor-review.feature +52 -72
- package/src/workflows/feature/review-answers.feature +90 -5
- package/src/workflows/feature/review-gate.feature +11 -53
- package/src/workflows/feature/reviewer-walkthrough.feature +29 -12
- package/src/workflows/feature/seam-rejection.feature +1 -6
- package/src/workflows/feature/seam.feature +1 -6
- package/src/workflows/feature/seam.test.ts +1 -1
- package/src/workflows/feature/seam.ts +2 -3
- package/src/workflows/feature/severity-budget.feature +7 -7
- package/src/workflows/feature/severity-sorted-review.feature +50 -54
- package/src/workflows/feature/slice-findings.feature +5 -15
- package/src/workflows/feature/slicing.feature +4 -24
- package/src/workflows/feature/standards.feature +0 -4
- package/src/workflows/shared/review.ts +26 -6
- package/src/workflows/shared/text.test.ts +45 -11
- package/src/workflows/shared/text.ts +45 -38
- package/src/workflows/feature/coverage.feature +0 -165
- 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+)
|
|
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 } :
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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.
|
|
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
|
|
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.
|
|
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
|
-
##
|
|
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
|
-
##
|
|
130
|
+
## Walkthrough
|
|
133
131
|
|
|
134
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
|
5
|
-
a person
|
|
6
|
-
|
|
7
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|