@pmelab/gtd 34.0.0 → 36.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 +35 -26
- package/dist/chunks/{reserved-BcJgt5_R.mjs → reserved-BAv71I4i.mjs} +43 -10
- package/dist/chunks/{tail-CM_fa93v.mjs → tail-kar1zhOb.mjs} +1 -1
- package/dist/flows.mjs +15 -10
- package/dist/gtd.bundle.mjs +14 -9
- package/dist/testkit.mjs +43 -23
- package/dist/workflows/cleanup.mjs +2 -2
- package/dist/workflows/feature.mjs +97 -20
- 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 +152 -38
- package/package.json +1 -1
- package/skills/authoring/SKILL.md +3 -3
- package/src/flows/scripts.ts +31 -9
- package/src/testkit/FlowScripts.test.ts +58 -0
- package/src/testkit/FlowScripts.ts +61 -24
- package/src/workflows/feature/acceptance-criteria.feature +5 -1
- package/src/workflows/feature/coverage.feature +164 -0
- package/src/workflows/feature/coverage.ts +106 -0
- package/src/workflows/feature/fast-path.feature +17 -20
- package/src/workflows/feature/feature.test.ts +25 -4
- package/src/workflows/feature/feature.ts +13 -9
- package/src/workflows/feature/flag-mode.feature +23 -10
- package/src/workflows/feature/lens-models.feature +11 -1
- package/src/workflows/feature/naive-acceptance.feature +2 -2
- package/src/workflows/feature/one-step-land.feature +16 -13
- package/src/workflows/feature/quality-unresolved.feature +11 -1
- package/src/workflows/feature/refactor-absorbs.feature +6 -1
- package/src/workflows/feature/refactor-first.feature +6 -1
- package/src/workflows/feature/refactor-review.feature +24 -0
- package/src/workflows/feature/risk-tier.feature +12 -4
- package/src/workflows/feature/seam-rejection.feature +10 -10
- package/src/workflows/feature/seam.feature +35 -27
- package/src/workflows/feature/seam.test.ts +12 -4
- package/src/workflows/feature/seam.ts +42 -32
- package/src/workflows/review/review-door.feature +18 -5
- package/src/workflows/shared/text.test.ts +8 -0
- package/src/workflows/shared/text.ts +54 -9
|
@@ -17,14 +17,15 @@ import * as t from "../shared/text.js"
|
|
|
17
17
|
import { skipDesign, statedCriteria, type StatedCriteria } from "./criteria.js"
|
|
18
18
|
import { design } from "./planning.js"
|
|
19
19
|
import { buildTail, isCode, reUnwind, type ReviewOutcome } from "./review.js"
|
|
20
|
-
import { implement, seamBuild
|
|
20
|
+
import { implement, seamBuild } from "./seam.js"
|
|
21
21
|
import { recordRisk, riskTierOn } from "./tier.js"
|
|
22
22
|
|
|
23
23
|
// The ordinary start. Any change to the tree starts a process: `idle` →
|
|
24
24
|
// `unwind` reverts the sketch (its intent survives in history) → a
|
|
25
|
-
// green-baseline gate → design → a
|
|
26
|
-
//
|
|
27
|
-
//
|
|
25
|
+
// green-baseline gate → design → a naive pass, judged with `flagMode` on: it
|
|
26
|
+
// lands as the implementation, or (refactoring first when the judge asks) is
|
|
27
|
+
// built fresh from → the health loop → the quality lap, and the episode ends
|
|
28
|
+
// back at `idle`. Human review is the `review` door's.
|
|
28
29
|
|
|
29
30
|
/** Revert the sketch that started the process out of the working tree; its intent survives in history. */
|
|
30
31
|
export const unwind = (): Promise<void> => {
|
|
@@ -36,14 +37,17 @@ export const unwind = (): Promise<void> => {
|
|
|
36
37
|
|
|
37
38
|
export { reUnwind }
|
|
38
39
|
|
|
39
|
-
/** A
|
|
40
|
+
/** A naive pass (judged only with `flagMode` on), then implement and the quality lap; design must have run since `firstBase`. */
|
|
40
41
|
export const buildFeature = async (firstBase: string): Promise<void> => {
|
|
41
42
|
const tier = riskTierOn() ? recordRisk() : undefined
|
|
42
|
-
const seam
|
|
43
|
-
? await seamBuild(firstBase)
|
|
44
|
-
: { base: firstBase }
|
|
43
|
+
const seam = await seamBuild(firstBase)
|
|
45
44
|
await slice("feature", async () => {
|
|
46
|
-
await implement({
|
|
45
|
+
await implement({
|
|
46
|
+
reference: seam.reference,
|
|
47
|
+
tier,
|
|
48
|
+
afterRefactor: seam.refactored,
|
|
49
|
+
naive: seam.land === true ? seam.reference : undefined,
|
|
50
|
+
})
|
|
47
51
|
// An empty feature slice: the refactor carried the feature, so the lap covers the whole change.
|
|
48
52
|
const base =
|
|
49
53
|
seam.refactored === true && !changesSince(seam.base).some((c) => isCode(c.path))
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
@inmem
|
|
2
|
-
Feature: flag mode off
|
|
2
|
+
Feature: flag mode off lands the naive pass with no release flag, seam judge or refactor
|
|
3
3
|
|
|
4
4
|
`flagMode` is a factory option of the shipped workflows, on by default. Off,
|
|
5
5
|
the project ships without feature flags: no seam judge and no refactor run,
|
|
6
|
-
and the naive
|
|
6
|
+
and the naive pass itself lands, straight through the health loop and the
|
|
7
7
|
quality lap.
|
|
8
8
|
|
|
9
9
|
Background:
|
|
@@ -43,23 +43,33 @@ Feature: flag mode off builds a feature with no release flag, seam judge or refa
|
|
|
43
43
|
"""
|
|
44
44
|
And step "design.gate.answer" changes nothing
|
|
45
45
|
|
|
46
|
-
Scenario: flag mode off
|
|
46
|
+
Scenario: flag mode off lands the naive pass unjudged, and asks for no flag
|
|
47
47
|
When the process is driven
|
|
48
|
-
Then the process rests at "
|
|
48
|
+
Then the process rests at "seam.naive"
|
|
49
49
|
And the resting step's content contains "the quickest way that works"
|
|
50
|
-
And the resting step's content
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
And the resting step's content does not contain "release flag"
|
|
51
|
+
Given step "seam.naive" writes "src/calc.test.ts" with:
|
|
52
|
+
"""
|
|
53
|
+
it("[AC-1] subtracts", () => {})
|
|
54
|
+
"""
|
|
55
|
+
And step "seam.naive" writes "src/calc.ts" with:
|
|
53
56
|
"""
|
|
54
57
|
export const add = (a: number, b: number) => a + b
|
|
55
58
|
export const subtract = (a: number, b: number) => a - b
|
|
56
59
|
"""
|
|
60
|
+
And step "seam.check" changes nothing
|
|
61
|
+
And step "implement.applying" runs its script
|
|
57
62
|
And step "implement.health.check" changes nothing
|
|
58
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
|
+
"""
|
|
59
68
|
And step "build.quality.correctness.reviewing" changes nothing
|
|
60
69
|
When the process is driven
|
|
61
70
|
Then the process rests at "idle"
|
|
62
71
|
And "src/calc.ts" contains "subtract"
|
|
72
|
+
And "src/calc.test.ts" contains "[AC-1] subtracts"
|
|
63
73
|
And the commit subjects end with:
|
|
64
74
|
"""
|
|
65
75
|
chore: initial commit
|
|
@@ -68,9 +78,12 @@ Feature: flag mode off builds a feature with no release flag, seam judge or refa
|
|
|
68
78
|
gtd(check): unwind → start-gate.check
|
|
69
79
|
gtd(check): start-gate.check → design.triage
|
|
70
80
|
gtd(agent): design.triage → design.gate.answer
|
|
71
|
-
gtd(human): design.gate.answer →
|
|
72
|
-
gtd(agent):
|
|
73
|
-
gtd(check):
|
|
81
|
+
gtd(human): design.gate.answer → seam.naive
|
|
82
|
+
gtd(agent): seam.naive → seam.check
|
|
83
|
+
gtd(check): seam.check → implement.applying
|
|
84
|
+
gtd(check): implement.applying → implement.health.check
|
|
85
|
+
gtd(check): implement.health.check → implement.coverage
|
|
86
|
+
gtd(judge): implement.coverage → implement.closing
|
|
74
87
|
gtd(check): implement.closing → build.quality.correctness.reviewing
|
|
75
88
|
gtd(agent): build.quality.correctness.reviewing → idle
|
|
76
89
|
"""
|
|
@@ -37,13 +37,23 @@ Feature: each quality lens runs on its own model hint
|
|
|
37
37
|
- AC-1: `subtract(a, b)` returns `a - b`.
|
|
38
38
|
"""
|
|
39
39
|
And step "design.gate.answer" changes nothing
|
|
40
|
-
And step "
|
|
40
|
+
And step "seam.naive" writes "src/calc.test.ts" with:
|
|
41
|
+
"""
|
|
42
|
+
it("[AC-1] subtracts", () => {})
|
|
43
|
+
"""
|
|
44
|
+
And step "seam.naive" writes "src/calc.ts" with:
|
|
41
45
|
"""
|
|
42
46
|
export const add = (a: number, b: number) => a + b
|
|
43
47
|
export const subtract = (a: number, b: number) => a - b
|
|
44
48
|
"""
|
|
49
|
+
And step "seam.check" changes nothing
|
|
50
|
+
And step "implement.applying" runs its script
|
|
45
51
|
And step "implement.health.check" changes nothing
|
|
46
52
|
And step "implement.closing" runs its script
|
|
53
|
+
And judge step "implement.coverage" answers:
|
|
54
|
+
"""
|
|
55
|
+
[{"id":"AC-1","answer":"yes","p":0.9}]
|
|
56
|
+
"""
|
|
47
57
|
|
|
48
58
|
Scenario: a hinted lens runs on its hint, every other lens on its default
|
|
49
59
|
When the process is driven
|
|
@@ -129,12 +129,12 @@ Feature: a naive pass ends only when a test names every criterion and the suite
|
|
|
129
129
|
"""
|
|
130
130
|
And step "seam.check" from now on changes nothing
|
|
131
131
|
When the process is driven
|
|
132
|
-
Then the process rests at "implement.
|
|
132
|
+
Then the process rests at "implement.applying"
|
|
133
133
|
And the commit subjects end with:
|
|
134
134
|
"""
|
|
135
135
|
gtd(human): design.gate.answer → seam.naive
|
|
136
136
|
gtd(agent): seam.naive → seam.check
|
|
137
137
|
gtd(check): seam.check → seam.naive
|
|
138
138
|
gtd(agent): seam.naive → seam.check
|
|
139
|
-
gtd(check): seam.check → implement.
|
|
139
|
+
gtd(check): seam.check → implement.applying
|
|
140
140
|
"""
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# One SDLC path per file, so a changed path reds exactly one fixture — do not merge.
|
|
2
2
|
@inmem
|
|
3
|
-
Feature: a naive pass the judge rules land
|
|
3
|
+
Feature: a naive pass the judge rules land is itself the implementation
|
|
4
4
|
|
|
5
5
|
With GTD_FLAG_RISK_TIER off, a naive pass that
|
|
6
6
|
edits an existing source file is judged land: the process skips the approval
|
|
7
|
-
gate and any refactor,
|
|
8
|
-
back to idle, with no review. The flag is pinned here so the per-flag test runs never
|
|
7
|
+
gate and any refactor, applies the kept pass as it is — no build turn — and
|
|
8
|
+
runs the health loop and quality back to idle, with no review. The flag is pinned here so the per-flag test runs never
|
|
9
9
|
move it off this path.
|
|
10
10
|
|
|
11
11
|
Background:
|
|
@@ -53,18 +53,20 @@ Feature: a naive pass the judge rules land goes straight to implement with no se
|
|
|
53
53
|
"""
|
|
54
54
|
[{"id":"shape","answer":"land","p":0.9}]
|
|
55
55
|
"""
|
|
56
|
-
And step "implement.
|
|
57
|
-
"""
|
|
58
|
-
export const greeting = "Hello, world!"
|
|
59
|
-
"""
|
|
56
|
+
And step "implement.applying" runs its script
|
|
60
57
|
And step "implement.health.check" changes nothing
|
|
61
58
|
And step "implement.closing" runs its script
|
|
59
|
+
And judge step "implement.coverage" answers:
|
|
60
|
+
"""
|
|
61
|
+
[{"id":"AC-1","answer":"yes","p":0.9}]
|
|
62
|
+
"""
|
|
62
63
|
And step "build.quality.correctness.reviewing" changes nothing
|
|
63
64
|
|
|
64
|
-
Scenario: a land judgment runs idle to idle with no
|
|
65
|
+
Scenario: a land judgment applies the naive pass and runs idle to idle with no rebuild
|
|
65
66
|
When the process is driven
|
|
66
67
|
Then the process rests at "idle"
|
|
67
|
-
And "src/greeting.ts" contains "Hello, world
|
|
68
|
+
And "src/greeting.ts" contains "Hello, world"
|
|
69
|
+
And "src/acceptance.test.ts" contains "[AC-1] holds"
|
|
68
70
|
And the commit subjects end with:
|
|
69
71
|
"""
|
|
70
72
|
gtd(human): idle → unwind
|
|
@@ -74,15 +76,16 @@ Feature: a naive pass the judge rules land goes straight to implement with no se
|
|
|
74
76
|
gtd(human): design.gate.answer → seam.naive
|
|
75
77
|
gtd(agent): seam.naive → seam.check
|
|
76
78
|
gtd(check): seam.check → seam.judge
|
|
77
|
-
gtd(judge): seam.judge → implement.
|
|
78
|
-
gtd(
|
|
79
|
-
gtd(check): implement.health.check → implement.
|
|
79
|
+
gtd(judge): seam.judge → implement.applying
|
|
80
|
+
gtd(check): implement.applying → implement.health.check
|
|
81
|
+
gtd(check): implement.health.check → implement.coverage
|
|
82
|
+
gtd(judge): implement.coverage → implement.closing
|
|
80
83
|
gtd(check): implement.closing → build.quality.correctness.reviewing
|
|
81
84
|
gtd(agent): build.quality.correctness.reviewing → idle
|
|
82
85
|
"""
|
|
83
86
|
And the commit "gtd(human): idle → unwind" has a body containing "Gtd-Var: flag_risk_tier=0"
|
|
84
87
|
And the commit "gtd(agent): seam.naive → seam.check" has a body containing "Gtd-Kept:"
|
|
85
|
-
And the commit "gtd(judge): seam.judge → implement.
|
|
88
|
+
And the commit "gtd(judge): seam.judge → implement.applying" has a body containing "\"answer\":\"land\""
|
|
86
89
|
And no commit body contains "Gtd-Approved:"
|
|
87
90
|
And the output lines of gtd "slices" start with:
|
|
88
91
|
"""
|
|
@@ -37,13 +37,23 @@ Feature: quality findings left unresolved hold a feature process short of idle
|
|
|
37
37
|
- AC-1: subtract(a, b) returns a - b.
|
|
38
38
|
"""
|
|
39
39
|
And step "design.gate.answer" changes nothing
|
|
40
|
-
And step "
|
|
40
|
+
And step "seam.naive" writes "src/calc.test.ts" with:
|
|
41
|
+
"""
|
|
42
|
+
it("[AC-1] subtracts", () => {})
|
|
43
|
+
"""
|
|
44
|
+
And step "seam.naive" writes "src/calc.ts" with:
|
|
41
45
|
"""
|
|
42
46
|
export const add = (a: number, b: number) => a + b
|
|
43
47
|
export const subtract = (a: number, b: number) => a - b
|
|
44
48
|
"""
|
|
49
|
+
And step "seam.check" changes nothing
|
|
50
|
+
And step "implement.applying" runs its script
|
|
45
51
|
And step "implement.health.check" changes nothing
|
|
46
52
|
And step "implement.closing" runs its script
|
|
53
|
+
And judge step "implement.coverage" answers:
|
|
54
|
+
"""
|
|
55
|
+
[{"id":"AC-1","answer":"yes","p":0.9}]
|
|
56
|
+
"""
|
|
47
57
|
|
|
48
58
|
Scenario: findings the fix cap left unresolved rest at build.quality-unresolved
|
|
49
59
|
Given step "build.quality.correctness.reviewing" writes ".gtd/QUALITY.md" with:
|
|
@@ -94,6 +94,10 @@ Feature: a refactor that carried the whole feature still gets a quality lap over
|
|
|
94
94
|
And step "implement.building" changes nothing
|
|
95
95
|
And step "implement.health.check" changes nothing
|
|
96
96
|
And step "implement.closing" runs its script
|
|
97
|
+
And judge step "implement.coverage" answers:
|
|
98
|
+
"""
|
|
99
|
+
[{"id":"AC-1","answer":"yes","p":0.9}]
|
|
100
|
+
"""
|
|
97
101
|
When gtd lands
|
|
98
102
|
And the process is driven
|
|
99
103
|
Then the process rests at "build.quality.correctness.reviewing"
|
|
@@ -109,7 +113,8 @@ Feature: a refactor that carried the whole feature still gets a quality lap over
|
|
|
109
113
|
gtd(human): refactor.build.review.await-review → refactor.build.review.closing
|
|
110
114
|
gtd(check): refactor.build.review.closing → implement.building
|
|
111
115
|
gtd(agent): implement.building → implement.health.check
|
|
112
|
-
gtd(check): implement.health.check → implement.
|
|
116
|
+
gtd(check): implement.health.check → implement.coverage
|
|
117
|
+
gtd(judge): implement.coverage → implement.closing
|
|
113
118
|
gtd(check): implement.closing → build.quality.correctness.reviewing
|
|
114
119
|
gtd(agent): build.quality.correctness.reviewing → idle
|
|
115
120
|
"""
|
|
@@ -108,6 +108,10 @@ Feature: a refactor-first judgment walks one fixed path to idle
|
|
|
108
108
|
"""
|
|
109
109
|
And step "implement.health.check" changes nothing
|
|
110
110
|
And step "implement.closing" runs its script
|
|
111
|
+
And judge step "implement.coverage" answers:
|
|
112
|
+
"""
|
|
113
|
+
[{"id":"AC-1","answer":"yes","p":0.9}]
|
|
114
|
+
"""
|
|
111
115
|
When the process is driven
|
|
112
116
|
Then the process rests at "idle"
|
|
113
117
|
And "src/calc.ts" contains "op(a, b, 1)"
|
|
@@ -130,7 +134,8 @@ Feature: a refactor-first judgment walks one fixed path to idle
|
|
|
130
134
|
gtd(human): refactor.build.review.await-review → refactor.build.review.closing
|
|
131
135
|
gtd(check): refactor.build.review.closing → implement.building
|
|
132
136
|
gtd(agent): implement.building → implement.health.check
|
|
133
|
-
gtd(check): implement.health.check → implement.
|
|
137
|
+
gtd(check): implement.health.check → implement.coverage
|
|
138
|
+
gtd(judge): implement.coverage → implement.closing
|
|
134
139
|
gtd(check): implement.closing → idle
|
|
135
140
|
"""
|
|
136
141
|
And the commit "gtd(human): idle → unwind" has a body containing "Gtd-Var: flag_risk_tier=0"
|
|
@@ -347,6 +347,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
347
347
|
"""
|
|
348
348
|
And step "implement.health.check" changes nothing
|
|
349
349
|
And step "implement.closing" runs its script
|
|
350
|
+
And judge step "implement.coverage" answers:
|
|
351
|
+
"""
|
|
352
|
+
[{"id":"AC-1","answer":"yes","p":0.9}]
|
|
353
|
+
"""
|
|
350
354
|
When the process is driven
|
|
351
355
|
Then the process rests at "refactor.build.review.await-review"
|
|
352
356
|
Given a file ".gtd/REVIEW.md" with:
|
|
@@ -636,6 +640,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
636
640
|
"""
|
|
637
641
|
And step "implement.health.check" changes nothing
|
|
638
642
|
And step "implement.closing" runs its script
|
|
643
|
+
And judge step "implement.coverage" answers:
|
|
644
|
+
"""
|
|
645
|
+
[{"id":"AC-1","answer":"yes","p":0.9}]
|
|
646
|
+
"""
|
|
639
647
|
When the process is driven
|
|
640
648
|
Then the process rests at "refactor.build.review.await-review"
|
|
641
649
|
Given a file ".gtd/REVIEW.md" with:
|
|
@@ -711,6 +719,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
711
719
|
"""
|
|
712
720
|
And step "implement.health.check" changes nothing
|
|
713
721
|
And step "implement.closing" runs its script
|
|
722
|
+
And judge step "implement.coverage" answers:
|
|
723
|
+
"""
|
|
724
|
+
[{"id":"AC-1","answer":"yes","p":0.9}]
|
|
725
|
+
"""
|
|
714
726
|
When the process is driven
|
|
715
727
|
Then the process rests at "refactor.build.review.await-review"
|
|
716
728
|
Given a file ".gtd/REVIEW.md" with:
|
|
@@ -973,6 +985,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
973
985
|
"""
|
|
974
986
|
And step "implement.health.check" changes nothing
|
|
975
987
|
And step "implement.closing" runs its script
|
|
988
|
+
And judge step "implement.coverage" answers:
|
|
989
|
+
"""
|
|
990
|
+
[{"id":"AC-1","answer":"yes","p":0.9}]
|
|
991
|
+
"""
|
|
976
992
|
When the process is driven
|
|
977
993
|
Then the process rests at "refactor.build.review.await-review"
|
|
978
994
|
Given a file ".gtd/REVIEW.md" with:
|
|
@@ -1052,6 +1068,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
1052
1068
|
"""
|
|
1053
1069
|
And step "implement.health.check" changes nothing
|
|
1054
1070
|
And step "implement.closing" runs its script
|
|
1071
|
+
And judge step "implement.coverage" answers:
|
|
1072
|
+
"""
|
|
1073
|
+
[{"id":"AC-1","answer":"yes","p":0.9}]
|
|
1074
|
+
"""
|
|
1055
1075
|
When the process is driven
|
|
1056
1076
|
Then the process rests at "refactor.build.review.await-review"
|
|
1057
1077
|
Given a file ".gtd/REVIEW.md" with:
|
|
@@ -1226,6 +1246,10 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
1226
1246
|
"""
|
|
1227
1247
|
And step "implement.health.check" changes nothing
|
|
1228
1248
|
And step "implement.closing" runs its script
|
|
1249
|
+
And judge step "implement.coverage" answers:
|
|
1250
|
+
"""
|
|
1251
|
+
[{"id":"AC-1","answer":"yes","p":0.9}]
|
|
1252
|
+
"""
|
|
1229
1253
|
When the process is driven
|
|
1230
1254
|
Then the process rests at "refactor.build.review.await-review"
|
|
1231
1255
|
Given a file ".gtd/REVIEW.md" with:
|
|
@@ -133,7 +133,7 @@ Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_T
|
|
|
133
133
|
| low |
|
|
134
134
|
| high |
|
|
135
135
|
|
|
136
|
-
Scenario: the tier comes from the requirements the final design gate lap accepted
|
|
136
|
+
Scenario: the tier a rebuilt pass is told comes from the requirements the final design gate lap accepted
|
|
137
137
|
Given step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
|
|
138
138
|
"""
|
|
139
139
|
# Requirements
|
|
@@ -146,7 +146,11 @@ Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_T
|
|
|
146
146
|
|
|
147
147
|
- AC-1: the change behaves as described.
|
|
148
148
|
"""
|
|
149
|
-
And step "seam.check"
|
|
149
|
+
And step "seam.check" writes "src/acceptance.test.ts" with:
|
|
150
|
+
"""
|
|
151
|
+
it("[AC-1] holds elsewhere", () => {})
|
|
152
|
+
"""
|
|
153
|
+
And step "implement.applying" runs its script
|
|
150
154
|
And step "seam.naive" writes "src/acceptance.test.ts" with:
|
|
151
155
|
"""
|
|
152
156
|
it("[AC-1] holds", () => {})
|
|
@@ -245,7 +249,7 @@ Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_T
|
|
|
245
249
|
And the resting step's content does not contain "## Production Signals"
|
|
246
250
|
|
|
247
251
|
|
|
248
|
-
Scenario: the flag-off twin keeps today's flag demand
|
|
252
|
+
Scenario: the flag-off twin keeps today's flag demand on a rebuilt pass
|
|
249
253
|
Given step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
|
|
250
254
|
"""
|
|
251
255
|
# Requirements
|
|
@@ -259,7 +263,11 @@ Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_T
|
|
|
259
263
|
- AC-1: the change behaves as described.
|
|
260
264
|
"""
|
|
261
265
|
And step "design.gate.answer" changes nothing
|
|
262
|
-
And step "seam.check"
|
|
266
|
+
And step "seam.check" writes "src/acceptance.test.ts" with:
|
|
267
|
+
"""
|
|
268
|
+
it("[AC-1] holds elsewhere", () => {})
|
|
269
|
+
"""
|
|
270
|
+
And step "implement.applying" runs its script
|
|
263
271
|
And step "seam.naive" writes "src/acceptance.test.ts" with:
|
|
264
272
|
"""
|
|
265
273
|
it("[AC-1] holds", () => {})
|
|
@@ -52,6 +52,10 @@ Feature: rejected naive passes walk one fixed path through the steer gate to idl
|
|
|
52
52
|
"""
|
|
53
53
|
And step "implement.health.check" changes nothing
|
|
54
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
|
+
"""
|
|
55
59
|
When the process is driven
|
|
56
60
|
Then the process rests at "seam.judge"
|
|
57
61
|
|
|
@@ -93,12 +97,7 @@ Feature: rejected naive passes walk one fixed path through the steer gate to idl
|
|
|
93
97
|
"""
|
|
94
98
|
[{"id":"shape","answer":"land","p":0.9}]
|
|
95
99
|
"""
|
|
96
|
-
And step "implement.
|
|
97
|
-
"""
|
|
98
|
-
export const add = (a: number, b: number) => a + b
|
|
99
|
-
export const subtract = (a: number, b: number) => a - b
|
|
100
|
-
export const SUBTRACT = true
|
|
101
|
-
"""
|
|
100
|
+
And step "implement.applying" runs its script
|
|
102
101
|
When gtd lands
|
|
103
102
|
And the process is driven
|
|
104
103
|
Then the process rests at "idle"
|
|
@@ -121,16 +120,17 @@ Feature: rejected naive passes walk one fixed path through the steer gate to idl
|
|
|
121
120
|
gtd(human): seam.steer → seam.naive
|
|
122
121
|
gtd(agent): seam.naive → seam.check
|
|
123
122
|
gtd(check): seam.check → seam.judge
|
|
124
|
-
gtd(judge): seam.judge → implement.
|
|
125
|
-
gtd(
|
|
126
|
-
gtd(check): implement.health.check → implement.
|
|
123
|
+
gtd(judge): seam.judge → implement.applying
|
|
124
|
+
gtd(check): implement.applying → implement.health.check
|
|
125
|
+
gtd(check): implement.health.check → implement.coverage
|
|
126
|
+
gtd(judge): implement.coverage → implement.closing
|
|
127
127
|
gtd(check): implement.closing → idle
|
|
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:"
|
|
131
131
|
And the commit "gtd(judge): seam.judge → seam.naive" has a body containing "\"answer\":\"reject\""
|
|
132
132
|
And the commit "gtd(judge): seam.judge → seam.steer" has a body containing "\"answer\":\"reject\""
|
|
133
|
-
And the commit "gtd(judge): seam.judge → implement.
|
|
133
|
+
And the commit "gtd(judge): seam.judge → implement.applying" has a body containing "\"answer\":\"land\""
|
|
134
134
|
And no commit body contains "Gtd-Approved:"
|
|
135
135
|
And the output lines of gtd "slices" start with:
|
|
136
136
|
"""
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Feature: the naive pass and seam judge decide how a feature is built
|
|
3
3
|
|
|
4
4
|
After design a naive pass is set aside under a kept ref, the judge reads its
|
|
5
|
-
diff, and the process either
|
|
6
|
-
first behind a human approval, or retries the naive pass.
|
|
5
|
+
diff, and the process either applies the pass as the implementation,
|
|
6
|
+
refactors the seam first behind a human approval, or retries the naive pass.
|
|
7
7
|
|
|
8
8
|
Background:
|
|
9
9
|
Given the shipped workflows, as gtd install scaffolds them
|
|
@@ -50,7 +50,7 @@ Feature: the naive pass and seam judge decide how a feature is built
|
|
|
50
50
|
"""
|
|
51
51
|
And step "design.gate.answer" changes nothing
|
|
52
52
|
|
|
53
|
-
Scenario: a land judgment
|
|
53
|
+
Scenario: a land judgment applies the naive pass with no seam gate, refactor or build turn
|
|
54
54
|
Given step "seam.check" changes nothing
|
|
55
55
|
And step "seam.naive" writes "src/acceptance.test.ts" with:
|
|
56
56
|
"""
|
|
@@ -66,7 +66,7 @@ Feature: the naive pass and seam judge decide how a feature is built
|
|
|
66
66
|
[{"id":"shape","answer":"land","p":0.9}]
|
|
67
67
|
"""
|
|
68
68
|
When the process is driven
|
|
69
|
-
Then the process rests at "implement.
|
|
69
|
+
Then the process rests at "implement.applying"
|
|
70
70
|
And the last commit body contains "Gtd-Judge:"
|
|
71
71
|
And the commit subjects end with:
|
|
72
72
|
"""
|
|
@@ -79,27 +79,34 @@ Feature: the naive pass and seam judge decide how a feature is built
|
|
|
79
79
|
gtd(human): design.gate.answer → seam.naive
|
|
80
80
|
gtd(agent): seam.naive → seam.check
|
|
81
81
|
gtd(check): seam.check → seam.judge
|
|
82
|
-
gtd(judge): seam.judge → implement.
|
|
82
|
+
gtd(judge): seam.judge → implement.applying
|
|
83
83
|
"""
|
|
84
84
|
|
|
85
|
-
Scenario:
|
|
86
|
-
Given step "seam.
|
|
87
|
-
And step "seam.naive" writes "src/acceptance.test.ts" with:
|
|
85
|
+
Scenario: a naive pass that no longer applies is built fresh, with the implement scope's skills
|
|
86
|
+
Given step "seam.naive" writes "src/acceptance.test.ts" with:
|
|
88
87
|
"""
|
|
89
88
|
it("[AC-1] holds", () => {})
|
|
90
89
|
"""
|
|
91
|
-
And step "seam.naive" writes "src/
|
|
90
|
+
And step "seam.naive" writes "src/subtract.ts" with:
|
|
92
91
|
"""
|
|
93
|
-
export const add = (a: number, b: number) => a + b
|
|
94
92
|
export const subtract = (a: number, b: number) => a - b
|
|
95
93
|
"""
|
|
96
|
-
And
|
|
94
|
+
And step "seam.check" writes "src/subtract.ts" with:
|
|
97
95
|
"""
|
|
98
|
-
|
|
96
|
+
export const subtract = (a: number, b: number) => b - a
|
|
99
97
|
"""
|
|
98
|
+
And step "implement.applying" runs its script
|
|
100
99
|
When the process is driven
|
|
101
100
|
Then the process rests at "implement.building"
|
|
102
101
|
And the resting step's content contains "my-tdd, my-runbook"
|
|
102
|
+
And the resting step's content contains "git show"
|
|
103
|
+
And ".gtd/FEEDBACK.md" contains "could not apply the naive pass"
|
|
104
|
+
And "src/subtract.ts" contains "b - a"
|
|
105
|
+
And the commit subjects end with:
|
|
106
|
+
"""
|
|
107
|
+
gtd(check): seam.check → implement.applying
|
|
108
|
+
gtd(check): implement.applying → implement.building
|
|
109
|
+
"""
|
|
103
110
|
|
|
104
111
|
Scenario: the naive pass lands as a marker commit and its turn stays off the branch
|
|
105
112
|
Given step "seam.check" changes nothing
|
|
@@ -122,7 +129,7 @@ Feature: the naive pass and seam judge decide how a feature is built
|
|
|
122
129
|
And the commit "gtd(agent): seam.naive → seam.check" has a body containing "Gtd-Kept:"
|
|
123
130
|
And "src/calc.ts" does not contain "subtract"
|
|
124
131
|
|
|
125
|
-
Scenario: the implementation is
|
|
132
|
+
Scenario: the implementation is the applied naive pass, a green check, then the requirements are closed out
|
|
126
133
|
Given step "seam.check" changes nothing
|
|
127
134
|
And step "seam.naive" writes "src/acceptance.test.ts" with:
|
|
128
135
|
"""
|
|
@@ -137,21 +144,22 @@ Feature: the naive pass and seam judge decide how a feature is built
|
|
|
137
144
|
"""
|
|
138
145
|
[{"id":"shape","answer":"land","p":0.9}]
|
|
139
146
|
"""
|
|
140
|
-
And step "implement.
|
|
141
|
-
"""
|
|
142
|
-
export const add = (a: number, b: number) => a + b
|
|
143
|
-
export const subtract = (a: number, b: number) => a - b
|
|
144
|
-
export const SUBTRACT_ENABLED = process.env.GTD_FLAG_SUBTRACT === "1"
|
|
145
|
-
"""
|
|
147
|
+
And step "implement.applying" runs its script
|
|
146
148
|
And step "implement.health.check" changes nothing
|
|
147
149
|
And step "implement.closing" runs its script
|
|
150
|
+
And judge step "implement.coverage" answers:
|
|
151
|
+
"""
|
|
152
|
+
[{"id":"AC-1","answer":"yes","p":0.9}]
|
|
153
|
+
"""
|
|
148
154
|
When the process is driven
|
|
149
155
|
Then the process rests at "idle"
|
|
156
|
+
And "src/calc.ts" contains "subtract"
|
|
150
157
|
And the commit subjects end with:
|
|
151
158
|
"""
|
|
152
|
-
gtd(judge): seam.judge → implement.
|
|
153
|
-
gtd(
|
|
154
|
-
gtd(check): implement.health.check → implement.
|
|
159
|
+
gtd(judge): seam.judge → implement.applying
|
|
160
|
+
gtd(check): implement.applying → implement.health.check
|
|
161
|
+
gtd(check): implement.health.check → implement.coverage
|
|
162
|
+
gtd(judge): implement.coverage → implement.closing
|
|
155
163
|
gtd(check): implement.closing → idle
|
|
156
164
|
"""
|
|
157
165
|
And ".gtd/REQUIREMENTS.md" does not exist
|
|
@@ -172,12 +180,12 @@ Feature: the naive pass and seam judge decide how a feature is built
|
|
|
172
180
|
it("adds", () => expect(2 + 2).toBe(4))
|
|
173
181
|
"""
|
|
174
182
|
When the process is driven
|
|
175
|
-
Then the process rests at "implement.
|
|
183
|
+
Then the process rests at "implement.applying"
|
|
176
184
|
And the commit subjects end with:
|
|
177
185
|
"""
|
|
178
186
|
gtd(human): design.gate.answer → seam.naive
|
|
179
187
|
gtd(agent): seam.naive → seam.check
|
|
180
|
-
gtd(check): seam.check → implement.
|
|
188
|
+
gtd(check): seam.check → implement.applying
|
|
181
189
|
"""
|
|
182
190
|
|
|
183
191
|
Scenario: a naive pass adding a glob-named file does not hide a modified sibling
|
|
@@ -253,7 +261,7 @@ Feature: the naive pass and seam judge decide how a feature is built
|
|
|
253
261
|
gtd(judge): seam.judge → seam.steer
|
|
254
262
|
"""
|
|
255
263
|
|
|
256
|
-
Scenario: a clean landing at the steer gate overrules, with no seam gate and no refactor
|
|
264
|
+
Scenario: a clean landing at the steer gate overrules and applies the pass, with no seam gate and no refactor
|
|
257
265
|
Given step "seam.check" changes nothing
|
|
258
266
|
And step "seam.naive" writes "src/acceptance.test.ts" with:
|
|
259
267
|
"""
|
|
@@ -270,9 +278,9 @@ Feature: the naive pass and seam judge decide how a feature is built
|
|
|
270
278
|
When the process is driven
|
|
271
279
|
Then the process rests at "seam.steer"
|
|
272
280
|
When gtd lands
|
|
273
|
-
Then the process rests at "implement.
|
|
281
|
+
Then the process rests at "implement.applying"
|
|
274
282
|
And the commit subjects end with:
|
|
275
283
|
"""
|
|
276
284
|
gtd(judge): seam.judge → seam.steer
|
|
277
|
-
gtd(human): seam.steer → implement.
|
|
285
|
+
gtd(human): seam.steer → implement.applying
|
|
278
286
|
"""
|
|
@@ -321,13 +321,19 @@ const driveSeam = async (
|
|
|
321
321
|
}
|
|
322
322
|
|
|
323
323
|
describe("seamBuild", () => {
|
|
324
|
-
it("land resolves the kept tip with the caller's base and enters no slice", async () => {
|
|
324
|
+
it("land resolves the kept tip to land, with the caller's base, and enters no slice", async () => {
|
|
325
325
|
const h = await driveSeam("land")
|
|
326
|
-
expect(h.outcome).toEqual({ reference: "abc", base: "c-base" })
|
|
326
|
+
expect(h.outcome).toEqual({ reference: "abc", base: "c-base", land: true })
|
|
327
327
|
expect(h.slices).toEqual([])
|
|
328
328
|
expect(h.names).toEqual(["seam.naive", "seam.check", "seam.judge"])
|
|
329
329
|
})
|
|
330
330
|
|
|
331
|
+
it("with flagMode off resolves a vetted pass to land with no judge", async () => {
|
|
332
|
+
const h = await driveSeam("reject", undefined, { flagMode: "false" })
|
|
333
|
+
expect(h.outcome).toEqual({ reference: "abc", base: "c-base", land: true })
|
|
334
|
+
expect(h.names).toEqual(["seam.naive", "seam.check"])
|
|
335
|
+
})
|
|
336
|
+
|
|
331
337
|
it("a red check retries the pass, and the judge sees it only once green", async () => {
|
|
332
338
|
const h = await driveSeam("land", undefined, {}, 1)
|
|
333
339
|
expect(h.names).toEqual(["seam.naive", "seam.check", "seam.naive", "seam.check", "seam.judge"])
|
|
@@ -355,7 +361,7 @@ describe("seamBuild", () => {
|
|
|
355
361
|
"seam.clear",
|
|
356
362
|
"seam.judge",
|
|
357
363
|
])
|
|
358
|
-
expect(h.outcome).toEqual({ reference: "abc", base: "c-base" })
|
|
364
|
+
expect(h.outcome).toEqual({ reference: "abc", base: "c-base", land: true })
|
|
359
365
|
})
|
|
360
366
|
|
|
361
367
|
it("refactor-first runs the reviewed refactor in slice refactor and resolves HEAD after it", async () => {
|
|
@@ -417,7 +423,9 @@ describe("implement", () => {
|
|
|
417
423
|
{
|
|
418
424
|
step: (request: StepRequest) => {
|
|
419
425
|
requests.push(request)
|
|
420
|
-
return Promise.resolve(
|
|
426
|
+
return Promise.resolve(
|
|
427
|
+
request.kind === "judge" ? { answers: {}, truncated: [] } : undefined,
|
|
428
|
+
)
|
|
421
429
|
},
|
|
422
430
|
pushScope: () => undefined,
|
|
423
431
|
popScope: () => undefined,
|