@pmelab/gtd 39.0.0 → 40.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 +54 -53
- package/dist/chunks/{reserved-B6tTYjeb.mjs → reserved-Qt5FM6Ia.mjs} +7 -5
- package/dist/chunks/{tail-_CZTP7Hu.mjs → tail-tAHx_AHe.mjs} +1 -1
- package/dist/workflows/cleanup.mjs +2 -2
- package/dist/workflows/feature.mjs +98 -37
- package/dist/workflows/fix.mjs +2 -2
- package/dist/workflows/review.mjs +2 -2
- package/dist/workflows/rollout.mjs +1 -1
- package/dist/workflows.mjs +103 -40
- package/package.json +1 -1
- package/skills/authoring/SKILL.md +3 -2
- package/src/workflows/feature/coverage.feature +5 -5
- package/src/workflows/feature/criteria.test.ts +20 -1
- package/src/workflows/feature/criteria.ts +24 -0
- package/src/workflows/feature/fast-path.feature +4 -4
- package/src/workflows/feature/feature.ts +82 -22
- package/src/workflows/feature/flag-mode.feature +2 -2
- package/src/workflows/feature/one-step-land.feature +4 -4
- package/src/workflows/feature/planning.ts +3 -2
- package/src/workflows/feature/quality-unresolved.feature +6 -6
- 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 +2 -2
- package/src/workflows/feature/refactor-review.feature +8 -8
- package/src/workflows/feature/review-gate.feature +271 -0
- package/src/workflows/feature/seam-rejection.feature +4 -4
- package/src/workflows/feature/seam.feature +2 -2
- package/src/workflows/feature/seam.ts +17 -7
- package/src/workflows/feature/slicing.feature +63 -4
- package/src/workflows/shared/text.ts +7 -5
- package/src/workflows/review/review-door.feature +0 -121
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
@inmem
|
|
2
|
-
Feature: quality findings left unresolved hold a feature process short of
|
|
2
|
+
Feature: quality findings left unresolved hold a feature process short of its review
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
When the quality lap's fix cap leaves `.gtd/QUALITY.md` behind, the process
|
|
5
|
+
rests for a person instead of handing findings nobody acted on to the
|
|
6
|
+
human review.
|
|
7
7
|
|
|
8
8
|
Background:
|
|
9
9
|
Given the shipped workflows, as gtd install scaffolds them
|
|
@@ -97,10 +97,10 @@ Feature: quality findings left unresolved hold a feature process short of idle
|
|
|
97
97
|
And step "build.health.check" changes nothing
|
|
98
98
|
When gtd lands
|
|
99
99
|
And the process is driven
|
|
100
|
-
Then the process rests at "
|
|
100
|
+
Then the process rests at "build.review.reviewing"
|
|
101
101
|
And the commit subjects end with:
|
|
102
102
|
"""
|
|
103
103
|
gtd(check): build.health.check → build.quality-unresolved
|
|
104
104
|
gtd(human): build.quality-unresolved → build.health.check
|
|
105
|
-
gtd(check): build.health.check →
|
|
105
|
+
gtd(check): build.health.check → build.review.reviewing
|
|
106
106
|
"""
|
|
@@ -42,7 +42,7 @@ Feature: a refactor that carried the whole feature still gets a quality lap over
|
|
|
42
42
|
"""
|
|
43
43
|
And step "design.gate.answer" changes nothing
|
|
44
44
|
|
|
45
|
-
Scenario: a tests-only implement turn after a refactor that did it all reaches the quality lap and
|
|
45
|
+
Scenario: a tests-only implement turn after a refactor that did it all reaches the quality lap and the review
|
|
46
46
|
Given step "seam.check" changes nothing
|
|
47
47
|
And step "seam.naive" writes "src/acceptance.test.ts" with:
|
|
48
48
|
"""
|
|
@@ -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 "
|
|
116
|
+
Then the process rests at "build.review.reviewing"
|
|
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 →
|
|
126
|
+
gtd(agent): build.quality.correctness.reviewing → build.review.reviewing
|
|
127
127
|
"""
|
|
128
128
|
And the output lines of gtd "slices" start with:
|
|
129
129
|
"""
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# One SDLC path per file, so a changed path reds exactly one fixture — do not merge.
|
|
2
2
|
@inmem
|
|
3
|
-
Feature: a refactor-first judgment walks one fixed path to
|
|
3
|
+
Feature: a refactor-first judgment walks one fixed path to the review gate
|
|
4
4
|
|
|
5
5
|
With GTD_FLAG_RISK_TIER off, a naive pass touching
|
|
6
6
|
an existing non-allowlisted file is ruled refactor-first, is refactored and
|
|
7
|
-
that refactor reviewed, and only then implemented
|
|
7
|
+
that refactor reviewed, and only then implemented and brought to the feature review. The flags are
|
|
8
8
|
pinned so the per-flag test runs never move it off its path.
|
|
9
9
|
|
|
10
10
|
Background:
|
|
@@ -41,7 +41,7 @@ Feature: a refactor-first judgment walks one fixed path to idle
|
|
|
41
41
|
"""
|
|
42
42
|
And step "design.gate.answer" changes nothing
|
|
43
43
|
|
|
44
|
-
Scenario: a refactor-first judgment runs refactor, its review, implement and
|
|
44
|
+
Scenario: a refactor-first judgment runs refactor, its review, implement and the quality lap to the feature review
|
|
45
45
|
Given step "seam.check" changes nothing
|
|
46
46
|
And step "seam.naive" writes "src/acceptance.test.ts" with:
|
|
47
47
|
"""
|
|
@@ -121,7 +121,7 @@ Feature: a refactor-first judgment walks one fixed path to idle
|
|
|
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 "
|
|
124
|
+
Then the process rests at "build.review.reviewing"
|
|
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:
|
|
@@ -145,7 +145,7 @@ Feature: a refactor-first judgment walks one fixed path to idle
|
|
|
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 →
|
|
148
|
+
gtd(check): implement.closing → build.review.reviewing
|
|
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:"
|
|
@@ -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 "
|
|
245
|
+
Then the process rests at "build.review.reviewing"
|
|
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
|
|
@@ -260,7 +260,7 @@ Feature: refactor-first writes a refactor note, refactors on its own, then rebui
|
|
|
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 →
|
|
263
|
+
gtd(check): implement.closing → build.review.reviewing
|
|
264
264
|
"""
|
|
265
265
|
And the output lines of gtd "slices" start with:
|
|
266
266
|
"""
|
|
@@ -4,7 +4,7 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
4
4
|
After a refactor-first judgment the refactor is built, quality-lapped and
|
|
5
5
|
reviewed in its own slice. Review edits re-run the refactor, never the design;
|
|
6
6
|
the feature slice that follows is quality-lapped from the refactor's
|
|
7
|
-
sign-off,
|
|
7
|
+
sign-off, then reviewed. The flags are pinned so the per-flag test runs never move it off
|
|
8
8
|
its path.
|
|
9
9
|
|
|
10
10
|
Background:
|
|
@@ -428,7 +428,7 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
428
428
|
Then the process rests at "refactor.build.review.await-review"
|
|
429
429
|
When gtd lands
|
|
430
430
|
And the process is driven
|
|
431
|
-
Then the process rests at "
|
|
431
|
+
Then the process rests at "build.review.reviewing"
|
|
432
432
|
|
|
433
433
|
Scenario: a question answered at the refactor review reaches the re-derived package as ### Answered Questions
|
|
434
434
|
When the process is driven
|
|
@@ -727,7 +727,7 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
727
727
|
"""
|
|
728
728
|
When gtd lands
|
|
729
729
|
And the process is driven
|
|
730
|
-
Then the process rests at "
|
|
730
|
+
Then the process rests at "build.review.reviewing"
|
|
731
731
|
And "src/calc.ts" contains "subtract"
|
|
732
732
|
|
|
733
733
|
Scenario: a praise-only one-shot footnote signs off and the feature slice follows
|
|
@@ -769,7 +769,7 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
769
769
|
"""
|
|
770
770
|
When gtd lands
|
|
771
771
|
And the process is driven
|
|
772
|
-
Then the process rests at "
|
|
772
|
+
Then the process rests at "build.review.reviewing"
|
|
773
773
|
And "src/calc.ts" contains "subtract"
|
|
774
774
|
|
|
775
775
|
Scenario: a one-shot footnote judged edit that collecting leaves out refuses naming its anchor
|
|
@@ -1084,7 +1084,7 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
1084
1084
|
"""
|
|
1085
1085
|
When gtd lands
|
|
1086
1086
|
And the process is driven
|
|
1087
|
-
Then the process rests at "
|
|
1087
|
+
Then the process rests at "build.review.reviewing"
|
|
1088
1088
|
And "src/calc.ts" contains "subtract"
|
|
1089
1089
|
|
|
1090
1090
|
Scenario: a praise-only refactor review still signs off and the feature slice follows
|
|
@@ -1119,7 +1119,7 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
1119
1119
|
"""
|
|
1120
1120
|
When gtd lands
|
|
1121
1121
|
And the process is driven
|
|
1122
|
-
Then the process rests at "
|
|
1122
|
+
Then the process rests at "build.review.reviewing"
|
|
1123
1123
|
And "src/calc.ts" contains "subtract"
|
|
1124
1124
|
|
|
1125
1125
|
Scenario: a nit fix in the refactor slice that changes a non-stray is refused, though a glob stray widens the write access
|
|
@@ -1309,11 +1309,11 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
1309
1309
|
And the resting step's content contains the hash of the commit "gtd(check): refactor.build.review.closing → implement.building"
|
|
1310
1310
|
Given step "build.quality.correctness.reviewing" changes nothing
|
|
1311
1311
|
When the process is driven
|
|
1312
|
-
Then the process rests at "
|
|
1312
|
+
Then the process rests at "build.review.reviewing"
|
|
1313
1313
|
And the commit subjects end with:
|
|
1314
1314
|
"""
|
|
1315
1315
|
gtd(check): implement.closing → build.quality.correctness.reviewing
|
|
1316
|
-
gtd(agent): build.quality.correctness.reviewing →
|
|
1316
|
+
gtd(agent): build.quality.correctness.reviewing → build.review.reviewing
|
|
1317
1317
|
"""
|
|
1318
1318
|
|
|
1319
1319
|
Rule: a refactor package never carries a test file, and demoted headings stop at ######
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
@inmem
|
|
2
|
+
Feature: a feature process ends at the human review
|
|
3
|
+
|
|
4
|
+
After the last slice's quality lap the process rests at the review gate,
|
|
5
|
+
`.gtd/REVIEW.md`. A sign-off ends the process. A note asking for a change in
|
|
6
|
+
behaviour starts a feedback lap — design, then implement with no new naive
|
|
7
|
+
pass or seam judge, the coverage judge over every criterion, the quality lap
|
|
8
|
+
— and the review again. Its design keeps a built criterion's ID and numbers
|
|
9
|
+
new behaviour above every ID handed out.
|
|
10
|
+
|
|
11
|
+
Background:
|
|
12
|
+
Given the shipped workflows, as gtd install scaffolds them
|
|
13
|
+
And an environment variable "GTD_QUALITYREVIEWS" set to ""
|
|
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
|
+
## Concerns
|
|
33
|
+
|
|
34
|
+
### Subtract
|
|
35
|
+
|
|
36
|
+
- `subtract(a, b)` returns `a - b`.
|
|
37
|
+
|
|
38
|
+
## Acceptance Criteria
|
|
39
|
+
|
|
40
|
+
- AC-1: subtract(a, b) returns a - b.
|
|
41
|
+
"""
|
|
42
|
+
And step "design.gate.answer" changes nothing
|
|
43
|
+
And step "seam.naive" writes "src/calc.test.ts" with:
|
|
44
|
+
"""
|
|
45
|
+
it("[AC-1] subtracts", () => {})
|
|
46
|
+
"""
|
|
47
|
+
And step "seam.naive" writes "src/calc.ts" with:
|
|
48
|
+
"""
|
|
49
|
+
export const add = (a: number, b: number) => a + b
|
|
50
|
+
export const subtract = (a: number, b: number) => a - b
|
|
51
|
+
"""
|
|
52
|
+
And step "seam.check" changes nothing
|
|
53
|
+
And step "implement.applying" runs its script
|
|
54
|
+
And step "implement.health.check" changes nothing
|
|
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
|
+
And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
|
|
61
|
+
"""
|
|
62
|
+
# Review: abc1234
|
|
63
|
+
|
|
64
|
+
<!-- base: 0000000 -->
|
|
65
|
+
|
|
66
|
+
## calc
|
|
67
|
+
|
|
68
|
+
- [ ] ./src/calc.ts#2-2
|
|
69
|
+
new subtract function
|
|
70
|
+
"""
|
|
71
|
+
And step "build.review.closing" runs its script
|
|
72
|
+
|
|
73
|
+
Scenario: a feature process ends at the review gate
|
|
74
|
+
When the process is driven
|
|
75
|
+
Then the process rests at "build.review.await-review"
|
|
76
|
+
And ".gtd/REQUIREMENTS.md" does not exist
|
|
77
|
+
And the resting step's content contains the hash of the commit "feat: add calculator"
|
|
78
|
+
And the commit subjects end with:
|
|
79
|
+
"""
|
|
80
|
+
gtd(judge): implement.coverage → implement.closing
|
|
81
|
+
gtd(check): implement.closing → build.review.reviewing
|
|
82
|
+
gtd(agent): build.review.reviewing → build.review.await-review
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
Scenario: a sign-off ends the process at idle
|
|
86
|
+
When the process is driven
|
|
87
|
+
Then the process rests at "build.review.await-review"
|
|
88
|
+
Given a file ".gtd/REVIEW.md" with:
|
|
89
|
+
"""
|
|
90
|
+
# Review: abc1234
|
|
91
|
+
|
|
92
|
+
<!-- base: 0000000 -->
|
|
93
|
+
|
|
94
|
+
## calc
|
|
95
|
+
|
|
96
|
+
- [x] ./src/calc.ts#2-2
|
|
97
|
+
new subtract function
|
|
98
|
+
"""
|
|
99
|
+
When gtd lands
|
|
100
|
+
And the process is driven
|
|
101
|
+
Then the process rests at "idle"
|
|
102
|
+
And ".gtd/REVIEW.md" does not exist
|
|
103
|
+
And the commit subjects end with:
|
|
104
|
+
"""
|
|
105
|
+
gtd(agent): build.review.reviewing → build.review.await-review
|
|
106
|
+
gtd(human): build.review.await-review → build.review.closing
|
|
107
|
+
gtd(check): build.review.closing → idle
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
Rule: a note asking for new behaviour runs the feedback lap
|
|
111
|
+
|
|
112
|
+
Background:
|
|
113
|
+
Given step "build.review.collecting" writes ".gtd/REQUIREMENTS.md" with:
|
|
114
|
+
"""
|
|
115
|
+
# Requirements
|
|
116
|
+
|
|
117
|
+
## Concerns
|
|
118
|
+
|
|
119
|
+
### Multiply
|
|
120
|
+
|
|
121
|
+
- Export `multiply()`.
|
|
122
|
+
"""
|
|
123
|
+
And step "build.review.collecting" writes ".gtd/REVIEW.md" with:
|
|
124
|
+
"""
|
|
125
|
+
# Review: abc1234
|
|
126
|
+
|
|
127
|
+
<!-- base: 0000000 -->
|
|
128
|
+
|
|
129
|
+
## calc
|
|
130
|
+
|
|
131
|
+
- [ ] ./src/calc.ts#2-2
|
|
132
|
+
new subtract function[^why]
|
|
133
|
+
|
|
134
|
+
[^why]:
|
|
135
|
+
- H: also export multiply
|
|
136
|
+
- A: noted in the requirements.
|
|
137
|
+
"""
|
|
138
|
+
And step "re-unwind" runs its script
|
|
139
|
+
When the process is driven
|
|
140
|
+
Then the process rests at "build.review.await-review"
|
|
141
|
+
Given a file ".gtd/REVIEW.md" with:
|
|
142
|
+
"""
|
|
143
|
+
# Review: abc1234
|
|
144
|
+
|
|
145
|
+
<!-- base: 0000000 -->
|
|
146
|
+
|
|
147
|
+
## calc
|
|
148
|
+
|
|
149
|
+
- [ ] ./src/calc.ts#2-2
|
|
150
|
+
new subtract function[^why]
|
|
151
|
+
|
|
152
|
+
[^why]:
|
|
153
|
+
- H: also export multiply
|
|
154
|
+
"""
|
|
155
|
+
When gtd lands
|
|
156
|
+
And the process is driven
|
|
157
|
+
Then the process rests at "build.review.await-review"
|
|
158
|
+
And ".gtd/REQUIREMENTS.md" contains "multiply"
|
|
159
|
+
Given a file ".gtd/REVIEW.md" with:
|
|
160
|
+
"""
|
|
161
|
+
# Review: abc1234
|
|
162
|
+
|
|
163
|
+
<!-- base: 0000000 -->
|
|
164
|
+
|
|
165
|
+
## calc
|
|
166
|
+
|
|
167
|
+
- [ ] ./src/calc.ts#2-2
|
|
168
|
+
new subtract function
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
Scenario: the lap keeps AC-1, adds AC-2, and covers both before the next review
|
|
172
|
+
Given step "design.triage" from now on changes nothing
|
|
173
|
+
And step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
|
|
174
|
+
"""
|
|
175
|
+
# Requirements
|
|
176
|
+
|
|
177
|
+
## Concerns
|
|
178
|
+
|
|
179
|
+
### Multiply
|
|
180
|
+
|
|
181
|
+
- `multiply(a, b)` returns `a * b`.
|
|
182
|
+
|
|
183
|
+
## Acceptance Criteria
|
|
184
|
+
|
|
185
|
+
- AC-1: subtract(a, b) returns a - b.
|
|
186
|
+
- AC-2: multiply(a, b) returns a * b.
|
|
187
|
+
"""
|
|
188
|
+
And step "implement.building" writes "src/calc.ts" with:
|
|
189
|
+
"""
|
|
190
|
+
export const add = (a: number, b: number) => a + b
|
|
191
|
+
export const subtract = (a: number, b: number) => a - b
|
|
192
|
+
export const multiply = (a: number, b: number) => a * b
|
|
193
|
+
"""
|
|
194
|
+
And step "implement.building" writes "src/multiply.test.ts" with:
|
|
195
|
+
"""
|
|
196
|
+
it("[AC-2] multiplies", () => {})
|
|
197
|
+
"""
|
|
198
|
+
And judge step "implement.coverage" answers:
|
|
199
|
+
"""
|
|
200
|
+
[{"id":"AC-1","answer":"yes","p":0.9},{"id":"AC-2","answer":"yes","p":0.9}]
|
|
201
|
+
"""
|
|
202
|
+
When gtd lands
|
|
203
|
+
And the process is driven
|
|
204
|
+
Then the process rests at "build.review.await-review"
|
|
205
|
+
And ".gtd/REQUIREMENTS.md" does not exist
|
|
206
|
+
And the commit "gtd(judge): implement.coverage → implement.closing" has a body containing "Gtd-Mark: covers=AC-1"
|
|
207
|
+
And the commit subjects end with:
|
|
208
|
+
"""
|
|
209
|
+
gtd(human): build.review.await-review → build.review.closing
|
|
210
|
+
gtd(check): build.review.closing → re-unwind
|
|
211
|
+
gtd(check): re-unwind → design.triage
|
|
212
|
+
gtd(agent): design.triage → design.gate.answer
|
|
213
|
+
gtd(human): design.gate.answer → implement.building
|
|
214
|
+
gtd(agent): implement.building → implement.health.check
|
|
215
|
+
gtd(check): implement.health.check → implement.coverage
|
|
216
|
+
gtd(judge): implement.coverage → implement.closing
|
|
217
|
+
gtd(check): implement.closing → build.review.reviewing
|
|
218
|
+
gtd(agent): build.review.reviewing → build.review.await-review
|
|
219
|
+
"""
|
|
220
|
+
|
|
221
|
+
Scenario: a design numbering new behaviour at or below an earlier ID is refused
|
|
222
|
+
Given step "design.triage" from now on changes nothing
|
|
223
|
+
And step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
|
|
224
|
+
"""
|
|
225
|
+
# Requirements
|
|
226
|
+
|
|
227
|
+
## Concerns
|
|
228
|
+
|
|
229
|
+
### Multiply
|
|
230
|
+
|
|
231
|
+
- `multiply(a, b)` returns `a * b`.
|
|
232
|
+
|
|
233
|
+
## Acceptance Criteria
|
|
234
|
+
|
|
235
|
+
- AC-0: multiply(a, b) returns a * b.
|
|
236
|
+
- AC-1: subtract(a, b) returns a - b.
|
|
237
|
+
"""
|
|
238
|
+
When gtd lands
|
|
239
|
+
Then driving the process is refused with "criteria-ids"
|
|
240
|
+
|
|
241
|
+
Scenario: the lap holds a new criterion to coverage
|
|
242
|
+
Given step "design.triage" from now on changes nothing
|
|
243
|
+
And step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
|
|
244
|
+
"""
|
|
245
|
+
# Requirements
|
|
246
|
+
|
|
247
|
+
## Concerns
|
|
248
|
+
|
|
249
|
+
### Multiply
|
|
250
|
+
|
|
251
|
+
- `multiply(a, b)` returns `a * b`.
|
|
252
|
+
|
|
253
|
+
## Acceptance Criteria
|
|
254
|
+
|
|
255
|
+
- AC-1: subtract(a, b) returns a - b.
|
|
256
|
+
- AC-2: multiply(a, b) returns a * b.
|
|
257
|
+
"""
|
|
258
|
+
And step "implement.building" writes "src/calc.ts" with:
|
|
259
|
+
"""
|
|
260
|
+
export const add = (a: number, b: number) => a + b
|
|
261
|
+
export const subtract = (a: number, b: number) => a - b
|
|
262
|
+
export const multiply = (a: number, b: number) => a * b
|
|
263
|
+
"""
|
|
264
|
+
And judge step "implement.coverage" answers:
|
|
265
|
+
"""
|
|
266
|
+
[{"id":"AC-1","answer":"yes","p":0.9},{"id":"AC-2","answer":"no","p":0.9}]
|
|
267
|
+
"""
|
|
268
|
+
When gtd lands
|
|
269
|
+
And the process is driven
|
|
270
|
+
Then the process rests at "implement.covering"
|
|
271
|
+
And the resting step's content contains "AC-2"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# One SDLC path per file, so a changed path reds exactly one fixture — do not merge.
|
|
2
2
|
@inmem
|
|
3
|
-
Feature: rejected naive passes walk one fixed path through the steer gate to
|
|
3
|
+
Feature: rejected naive passes walk one fixed path through the steer gate to the review gate
|
|
4
4
|
|
|
5
5
|
With GTD_FLAG_RISK_TIER off, three rejected naive
|
|
6
6
|
passes rest at the steer gate, where a human edit restarts the seam and the
|
|
@@ -40,7 +40,7 @@ Feature: rejected naive passes walk one fixed path through the steer gate to idl
|
|
|
40
40
|
"""
|
|
41
41
|
And step "design.gate.answer" changes nothing
|
|
42
42
|
|
|
43
|
-
Scenario: three rejects rest at the steer gate, a steered rerun lands and runs to
|
|
43
|
+
Scenario: three rejects rest at the steer gate, a steered rerun lands and runs to the review gate
|
|
44
44
|
Given step "seam.check" changes nothing
|
|
45
45
|
And step "seam.naive" writes "src/acceptance.test.ts" with:
|
|
46
46
|
"""
|
|
@@ -100,7 +100,7 @@ Feature: rejected naive passes walk one fixed path through the steer gate to idl
|
|
|
100
100
|
And step "implement.applying" runs its script
|
|
101
101
|
When gtd lands
|
|
102
102
|
And the process is driven
|
|
103
|
-
Then the process rests at "
|
|
103
|
+
Then the process rests at "build.review.reviewing"
|
|
104
104
|
And the commit subjects end with:
|
|
105
105
|
"""
|
|
106
106
|
gtd(human): idle → unwind
|
|
@@ -124,7 +124,7 @@ Feature: rejected naive passes walk one fixed path through the steer gate to idl
|
|
|
124
124
|
gtd(check): implement.applying → implement.health.check
|
|
125
125
|
gtd(check): implement.health.check → implement.coverage
|
|
126
126
|
gtd(judge): implement.coverage → implement.closing
|
|
127
|
-
gtd(check): implement.closing →
|
|
127
|
+
gtd(check): implement.closing → build.review.reviewing
|
|
128
128
|
"""
|
|
129
129
|
And the commit "gtd(human): idle → unwind" has a body containing "Gtd-Var: flag_risk_tier=0"
|
|
130
130
|
And the commit "gtd(agent): seam.naive → seam.check" has a body containing "Gtd-Kept:"
|
|
@@ -152,7 +152,7 @@ Feature: the naive pass and seam judge decide how a feature is built
|
|
|
152
152
|
[{"id":"AC-1","answer":"yes","p":0.9}]
|
|
153
153
|
"""
|
|
154
154
|
When the process is driven
|
|
155
|
-
Then the process rests at "
|
|
155
|
+
Then the process rests at "build.review.reviewing"
|
|
156
156
|
And "src/calc.ts" contains "subtract"
|
|
157
157
|
And the commit subjects end with:
|
|
158
158
|
"""
|
|
@@ -160,7 +160,7 @@ Feature: the naive pass and seam judge decide how a feature is built
|
|
|
160
160
|
gtd(check): implement.applying → implement.health.check
|
|
161
161
|
gtd(check): implement.health.check → implement.coverage
|
|
162
162
|
gtd(judge): implement.coverage → implement.closing
|
|
163
|
-
gtd(check): implement.closing →
|
|
163
|
+
gtd(check): implement.closing → build.review.reviewing
|
|
164
164
|
"""
|
|
165
165
|
And ".gtd/REQUIREMENTS.md" does not exist
|
|
166
166
|
|
|
@@ -283,7 +283,7 @@ export interface ImplementOptions {
|
|
|
283
283
|
/** Where the slice began: the coverage judge reads only the tests changed since. */
|
|
284
284
|
readonly base?: string | undefined
|
|
285
285
|
/** Not the last slice: `.gtd/REQUIREMENTS.md` and `.gtd/SLICES.md` stay for the next one. */
|
|
286
|
-
readonly more?: boolean | undefined
|
|
286
|
+
readonly more?: boolean | (() => boolean) | undefined
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
/** Resolves `false` when the tip no longer applies (the failure is in `.gtd/FEEDBACK.md`) or has nothing outside `.gtd/` to apply. */
|
|
@@ -351,14 +351,19 @@ export function implement(
|
|
|
351
351
|
tier?: RiskTier,
|
|
352
352
|
amend?: boolean,
|
|
353
353
|
): Promise<void>
|
|
354
|
-
export function implement(
|
|
354
|
+
export async function implement(
|
|
355
355
|
first?: string | ImplementOptions,
|
|
356
356
|
tier?: RiskTier,
|
|
357
357
|
amend?: boolean,
|
|
358
358
|
): Promise<void> {
|
|
359
|
-
|
|
360
|
-
typeof first === "object" && first !== null ? first : { reference: first, tier, amend }
|
|
361
|
-
|
|
359
|
+
await implementing(
|
|
360
|
+
typeof first === "object" && first !== null ? first : { reference: first, tier, amend },
|
|
361
|
+
)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/** `implement`, resolving with the criterion IDs the requirements listed when it closed. */
|
|
365
|
+
export const implementing = (options: ImplementOptions): Promise<readonly string[]> =>
|
|
366
|
+
scope("implement", async () => {
|
|
362
367
|
const since = head()
|
|
363
368
|
const acceptance = options.rebuild?.acceptance
|
|
364
369
|
const built = options.naive === undefined || !(await applied(options.naive))
|
|
@@ -372,9 +377,14 @@ export function implement(
|
|
|
372
377
|
built && acceptance !== undefined ? () => requireAcceptanceKept(acceptance) : undefined,
|
|
373
378
|
)
|
|
374
379
|
await requireCoverage(options.base, options.slice)
|
|
375
|
-
|
|
380
|
+
const ids = criterionIds(read(REQUIREMENTS) ?? "")
|
|
381
|
+
await closing(moreToBuild(options.more))
|
|
382
|
+
return ids
|
|
376
383
|
})
|
|
377
|
-
|
|
384
|
+
|
|
385
|
+
// Read at closing: a narrowing at `implement.oversized` may have emptied every later slice.
|
|
386
|
+
const moreToBuild = (more: ImplementOptions["more"]): boolean =>
|
|
387
|
+
typeof more === "function" ? more() : more === true
|
|
378
388
|
|
|
379
389
|
/** The last slice's closing, for a last slice a steer left with no criterion to build. */
|
|
380
390
|
export const closeOut = (): Promise<void> => scope("implement", () => closing(false))
|
|
@@ -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 "
|
|
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 →
|
|
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 "
|
|
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 →
|
|
132
|
+
gtd(check): implement.closing → build.review.reviewing
|
|
133
133
|
"""
|
|
134
134
|
And the output lines of gtd "slices" start with:
|
|
135
135
|
"""
|
|
@@ -223,3 +223,62 @@ Feature: a change with more criteria than the cap is built in coarse slices
|
|
|
223
223
|
- AC-2
|
|
224
224
|
"""
|
|
225
225
|
Then driving the process is refused with "wrote outside its write access"
|
|
226
|
+
|
|
227
|
+
Scenario: a steer that empties the last slice still ends at the review of the whole change
|
|
228
|
+
Given step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
|
|
229
|
+
"""
|
|
230
|
+
# Requirements
|
|
231
|
+
|
|
232
|
+
## Acceptance Criteria
|
|
233
|
+
|
|
234
|
+
- AC-1: subtract(a, b) returns a - b.
|
|
235
|
+
- AC-2: multiply(a, b) returns a * b.
|
|
236
|
+
- AC-3: divide(a, b) returns a / b.
|
|
237
|
+
"""
|
|
238
|
+
And step "design.slicing" writes ".gtd/SLICES.md" with:
|
|
239
|
+
"""
|
|
240
|
+
# Slices
|
|
241
|
+
|
|
242
|
+
## Subtract and divide
|
|
243
|
+
|
|
244
|
+
- AC-1
|
|
245
|
+
- AC-3
|
|
246
|
+
|
|
247
|
+
## Multiply
|
|
248
|
+
|
|
249
|
+
- AC-2
|
|
250
|
+
"""
|
|
251
|
+
And step "seam.naive" writes "src/sub.test.ts" with:
|
|
252
|
+
"""
|
|
253
|
+
it("[AC-1] subtracts", () => {})
|
|
254
|
+
"""
|
|
255
|
+
And judge step "implement.coverage" answers:
|
|
256
|
+
"""
|
|
257
|
+
[{"id":"AC-1","answer":"yes","p":0.9}]
|
|
258
|
+
"""
|
|
259
|
+
When the process is driven
|
|
260
|
+
Then the process rests at "seam.steer"
|
|
261
|
+
Given a file ".gtd/REQUIREMENTS.md" with:
|
|
262
|
+
"""
|
|
263
|
+
# Requirements
|
|
264
|
+
|
|
265
|
+
## Acceptance Criteria
|
|
266
|
+
|
|
267
|
+
- AC-1: subtract(a, b) returns a - b.
|
|
268
|
+
"""
|
|
269
|
+
When gtd lands
|
|
270
|
+
And the process is driven
|
|
271
|
+
Then the process rests at "build.review.reviewing"
|
|
272
|
+
And the commit subjects end with:
|
|
273
|
+
"""
|
|
274
|
+
gtd(human): seam.steer → seam.naive
|
|
275
|
+
gtd(agent): seam.naive → seam.check
|
|
276
|
+
gtd(check): seam.check → implement.applying
|
|
277
|
+
gtd(check): implement.applying → implement.health.check
|
|
278
|
+
gtd(check): implement.health.check → implement.coverage
|
|
279
|
+
gtd(judge): implement.coverage → implement.closing
|
|
280
|
+
gtd(check): implement.closing → build.review.reviewing
|
|
281
|
+
"""
|
|
282
|
+
And ".gtd/REQUIREMENTS.md" does not exist
|
|
283
|
+
And ".gtd/SLICES.md" does not exist
|
|
284
|
+
And the output of gtd "slices" does not contain "feature-2"
|