@pmelab/gtd 29.3.1 → 30.1.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 +64 -63
- package/claude/hooks/register.tsx +5 -0
- package/dist/chunks/{reserved-Dmpg6dAp.mjs → reserved-DDiiAZ8U.mjs} +35 -239
- package/dist/chunks/{tail-CLyE5VFR.mjs → tail-ILPlELuy.mjs} +1 -1
- package/dist/gtd.bundle.mjs +0 -5
- package/dist/testkit.mjs +0 -5
- package/dist/workflows/cleanup.mjs +2 -2
- package/dist/workflows/feature.mjs +17 -182
- 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 +47 -416
- package/package.json +1 -1
- package/skills/authoring/SKILL.md +15 -27
- package/src/cli/Cli.test.ts +6 -6
- package/src/edge/Edge.test.ts +7 -7
- package/src/flags/index.test.ts +0 -4
- package/src/flags/index.ts +0 -1
- package/src/workflow/load.test.ts +1 -1
- package/src/workflows/feature/fast-path.feature +1 -2
- package/src/workflows/feature/feature.test.ts +115 -63
- package/src/workflows/feature/feature.ts +21 -38
- package/src/workflows/feature/flag-mode.feature +157 -0
- package/src/workflows/feature/index.ts +0 -1
- package/src/workflows/feature/one-step-land.feature +4 -6
- package/src/workflows/feature/planning.ts +2 -27
- package/src/workflows/feature/refactor-absorbs.feature +1 -2
- package/src/workflows/feature/refactor-first.feature +1 -3
- package/src/workflows/feature/refactor-review.feature +0 -1
- package/src/workflows/feature/risk-tier.feature +2 -3
- package/src/workflows/feature/seam-rejection.feature +1 -3
- package/src/workflows/feature/seam.feature +4 -6
- package/src/workflows/feature/seam.ts +2 -0
- package/src/workflows/feature/steps.test.ts +0 -20
- package/src/workflows/feature/steps.ts +1 -49
- package/src/workflows/feature/{seam-pin.feature → tier-pin.feature} +17 -11
- package/src/workflows/feature/tier.test.ts +3 -5
- package/src/workflows/feature/tier.ts +2 -2
- package/src/workflows/index.ts +0 -1
- package/src/workflows/shared/access.test.ts +0 -2
- package/src/workflows/shared/access.ts +0 -2
- package/src/workflows/shared/options.test.ts +14 -3
- package/src/workflows/shared/options.ts +17 -2
- package/src/workflows/shared/prose.ts +4 -11
- package/src/workflows/shared/reserved.ts +2 -2
- package/src/workflows/shared/skills.test.ts +0 -11
- package/src/workflows/shared/skills.ts +2 -9
- package/src/workflows/shared/steps.ts +0 -1
- package/src/workflows/shared/text.test.ts +20 -104
- package/src/workflows/shared/text.ts +28 -229
- package/src/workflows/shared/vars.ts +2 -3
- package/src/workflows/feature/packages.test.ts +0 -368
- package/src/workflows/feature/packages.ts +0 -173
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
@inmem
|
|
2
|
+
Feature: flag mode off builds a feature with no release flag, seam judge or refactor
|
|
3
|
+
|
|
4
|
+
`flagMode` is a factory option of the shipped workflows, on by default. Off,
|
|
5
|
+
the project ships without feature flags: no seam judge and no refactor run,
|
|
6
|
+
and the naive implementation goes straight through the health loop and the
|
|
7
|
+
quality lap.
|
|
8
|
+
|
|
9
|
+
Background:
|
|
10
|
+
Given a gtd config with:
|
|
11
|
+
"""
|
|
12
|
+
import { feature } from "@pmelab/gtd/workflows/feature"
|
|
13
|
+
export { summary, steering, skills, access } from "@pmelab/gtd/workflows/feature"
|
|
14
|
+
export default feature({ flagMode: false })
|
|
15
|
+
"""
|
|
16
|
+
And an environment variable "GTD_QUALITYREVIEWS" set to "correctness"
|
|
17
|
+
And a file "src/calc.ts" with:
|
|
18
|
+
"""
|
|
19
|
+
export const add = (a: number, b: number) => a + b
|
|
20
|
+
"""
|
|
21
|
+
And the working tree is committed as "feat: add calculator"
|
|
22
|
+
And a file "TODO.md" with:
|
|
23
|
+
"""
|
|
24
|
+
# Add subtract
|
|
25
|
+
|
|
26
|
+
subtract(a, b) returns the difference.
|
|
27
|
+
"""
|
|
28
|
+
And step "unwind" changes nothing
|
|
29
|
+
And step "start-gate.check" changes nothing
|
|
30
|
+
And step "design.triage" writes ".gtd/REQUIREMENTS.md" with:
|
|
31
|
+
"""
|
|
32
|
+
# Requirements
|
|
33
|
+
|
|
34
|
+
## Concerns
|
|
35
|
+
|
|
36
|
+
### Subtract
|
|
37
|
+
|
|
38
|
+
- `subtract(a, b)` returns `a - b`.
|
|
39
|
+
"""
|
|
40
|
+
And step "design.gate.answer" changes nothing
|
|
41
|
+
|
|
42
|
+
Scenario: flag mode off skips the seam judge and the refactor, and asks for no flag
|
|
43
|
+
When the process is driven
|
|
44
|
+
Then the process rests at "implement.building"
|
|
45
|
+
And the resting step's content contains "the quickest way that works"
|
|
46
|
+
And the resting step's content contains "Add no release flag — this project ships without release flags"
|
|
47
|
+
And the resting step's content does not contain "new release flag"
|
|
48
|
+
Given step "implement.building" writes "src/calc.ts" with:
|
|
49
|
+
"""
|
|
50
|
+
export const add = (a: number, b: number) => a + b
|
|
51
|
+
export const subtract = (a: number, b: number) => a - b
|
|
52
|
+
"""
|
|
53
|
+
And step "implement.health.check" changes nothing
|
|
54
|
+
And step "implement.closing" runs its script
|
|
55
|
+
And step "build.quality.correctness.reviewing" changes nothing
|
|
56
|
+
When the process is driven
|
|
57
|
+
Then the process rests at "build.review.reviewing"
|
|
58
|
+
And "src/calc.ts" contains "subtract"
|
|
59
|
+
And the commit subjects end with:
|
|
60
|
+
"""
|
|
61
|
+
chore: initial commit
|
|
62
|
+
feat: add calculator
|
|
63
|
+
gtd(human): idle → unwind
|
|
64
|
+
gtd(check): unwind → start-gate.check
|
|
65
|
+
gtd(check): start-gate.check → design.triage
|
|
66
|
+
gtd(agent): design.triage → design.gate.answer
|
|
67
|
+
gtd(human): design.gate.answer → implement.building
|
|
68
|
+
gtd(agent): implement.building → implement.health.check
|
|
69
|
+
gtd(check): implement.health.check → implement.closing
|
|
70
|
+
gtd(check): implement.closing → build.quality.correctness.reviewing
|
|
71
|
+
gtd(agent): build.quality.correctness.reviewing → build.review.reviewing
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
Scenario: flag mode off asks for no flag on a feedback lap either
|
|
75
|
+
Given step "implement.building" writes "src/calc.ts" with:
|
|
76
|
+
"""
|
|
77
|
+
export const add = (a: number, b: number) => a + b
|
|
78
|
+
export const subtract = (a: number, b: number) => a - b
|
|
79
|
+
"""
|
|
80
|
+
And step "implement.health.check" changes nothing
|
|
81
|
+
And step "implement.closing" runs its script
|
|
82
|
+
And step "build.quality.correctness.reviewing" changes nothing
|
|
83
|
+
And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
|
|
84
|
+
"""
|
|
85
|
+
# Review: abc1234
|
|
86
|
+
|
|
87
|
+
<!-- base: 0000000 -->
|
|
88
|
+
|
|
89
|
+
## calc
|
|
90
|
+
|
|
91
|
+
- [ ] ./src/calc.ts#2-2
|
|
92
|
+
new subtract function
|
|
93
|
+
"""
|
|
94
|
+
When the process is driven
|
|
95
|
+
Then the process rests at "build.review.await-review"
|
|
96
|
+
Given a file ".gtd/REVIEW.md" with:
|
|
97
|
+
"""
|
|
98
|
+
# Review: abc1234
|
|
99
|
+
|
|
100
|
+
<!-- base: 0000000 -->
|
|
101
|
+
|
|
102
|
+
## calc
|
|
103
|
+
|
|
104
|
+
- [ ] ./src/calc.ts#2-2
|
|
105
|
+
new subtract function[^why]
|
|
106
|
+
|
|
107
|
+
[^why]:
|
|
108
|
+
- H: also export multiply
|
|
109
|
+
"""
|
|
110
|
+
And step "build.review.collecting" writes ".gtd/REQUIREMENTS.md" with:
|
|
111
|
+
"""
|
|
112
|
+
# Requirements
|
|
113
|
+
|
|
114
|
+
## Concerns
|
|
115
|
+
|
|
116
|
+
### Multiply
|
|
117
|
+
|
|
118
|
+
- Export `multiply()`.
|
|
119
|
+
"""
|
|
120
|
+
And step "build.review.collecting" writes ".gtd/REVIEW.md" with:
|
|
121
|
+
"""
|
|
122
|
+
# Review: abc1234
|
|
123
|
+
|
|
124
|
+
<!-- base: 0000000 -->
|
|
125
|
+
|
|
126
|
+
## calc
|
|
127
|
+
|
|
128
|
+
- [ ] ./src/calc.ts#2-2
|
|
129
|
+
new subtract function[^why]
|
|
130
|
+
|
|
131
|
+
[^why]:
|
|
132
|
+
- H: also export multiply
|
|
133
|
+
- A: noted in the requirements.
|
|
134
|
+
"""
|
|
135
|
+
When gtd lands
|
|
136
|
+
And the process is driven
|
|
137
|
+
Then the process rests at "build.review.await-review"
|
|
138
|
+
Given a file ".gtd/REVIEW.md" with:
|
|
139
|
+
"""
|
|
140
|
+
# Review: abc1234
|
|
141
|
+
|
|
142
|
+
<!-- base: 0000000 -->
|
|
143
|
+
|
|
144
|
+
## calc
|
|
145
|
+
|
|
146
|
+
- [ ] ./src/calc.ts#2-2
|
|
147
|
+
new subtract function
|
|
148
|
+
"""
|
|
149
|
+
And step "build.review.closing" runs its script
|
|
150
|
+
And step "re-unwind" runs its script
|
|
151
|
+
And step "implement.building" is no longer scripted
|
|
152
|
+
When gtd lands
|
|
153
|
+
And the process is driven
|
|
154
|
+
Then the process rests at "implement.building"
|
|
155
|
+
And the resting step's content contains "Add no release flag — this project ships without release flags"
|
|
156
|
+
And the resting step's content does not contain "release flag the earlier lap added"
|
|
157
|
+
And no commit body contains "Gtd-Kept:"
|
|
@@ -2,16 +2,15 @@
|
|
|
2
2
|
@inmem
|
|
3
3
|
Feature: a naive pass the judge rules land goes straight to implement with no seam gate
|
|
4
4
|
|
|
5
|
-
With
|
|
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
|
|
8
|
-
review back to idle. The
|
|
7
|
+
gate and any refactor, and runs implement, quality and
|
|
8
|
+
review back to idle. The flag is pinned here so the per-flag test runs never
|
|
9
9
|
move it off this path.
|
|
10
10
|
|
|
11
11
|
Background:
|
|
12
12
|
Given the shipped workflows, as gtd install scaffolds them
|
|
13
13
|
And an environment variable "GTD_QUALITYREVIEWS" set to "correctness"
|
|
14
|
-
And an environment variable "GTD_FLAG_NAIVE_PASS" set to "1"
|
|
15
14
|
And an environment variable "GTD_FLAG_RISK_TIER" set to "0"
|
|
16
15
|
And a file "src/greeting.ts" with:
|
|
17
16
|
"""
|
|
@@ -65,7 +64,7 @@ Feature: a naive pass the judge rules land goes straight to implement with no se
|
|
|
65
64
|
"""
|
|
66
65
|
And step "build.review.closing" runs its script
|
|
67
66
|
|
|
68
|
-
Scenario: a land judgment runs idle to idle with no seam gate
|
|
67
|
+
Scenario: a land judgment runs idle to idle with no seam gate or refactor
|
|
69
68
|
When the process is driven
|
|
70
69
|
Then the process rests at "build.review.await-review"
|
|
71
70
|
Given a file ".gtd/REVIEW.md" with:
|
|
@@ -100,7 +99,6 @@ Feature: a naive pass the judge rules land goes straight to implement with no se
|
|
|
100
99
|
gtd(human): build.review.await-review → build.review.closing
|
|
101
100
|
gtd(check): build.review.closing → idle
|
|
102
101
|
"""
|
|
103
|
-
And the commit "gtd(human): idle → unwind" has a body containing "Gtd-Var: flag_naive_pass=1"
|
|
104
102
|
And the commit "gtd(human): idle → unwind" has a body containing "Gtd-Var: flag_risk_tier=0"
|
|
105
103
|
And the commit "gtd(agent): seam.naive → seam.judge" has a body containing "Gtd-Kept:"
|
|
106
104
|
And the commit "gtd(judge): seam.judge → implement.building" has a body containing "\"answer\":\"land\""
|
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
changes,
|
|
3
3
|
hasThreadFor,
|
|
4
|
-
refuse,
|
|
5
4
|
requireAnswers,
|
|
6
5
|
requireReplies,
|
|
7
6
|
requireThreadsClosed,
|
|
8
7
|
requireProgress,
|
|
9
8
|
scope,
|
|
10
9
|
} from "../../flows/index.js"
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
answerProductQuestions,
|
|
14
|
-
answerTechnicalQuestions,
|
|
15
|
-
author,
|
|
16
|
-
decompose,
|
|
17
|
-
triage,
|
|
18
|
-
} from "./steps.js"
|
|
10
|
+
import { REQUIREMENTS } from "../shared/steps.js"
|
|
11
|
+
import { answerProductQuestions, triage } from "./steps.js"
|
|
19
12
|
|
|
20
13
|
/**
|
|
21
14
|
* Always stop for the human. Resolves `true` when the round changed anything
|
|
@@ -40,21 +33,3 @@ export const design = (base: string): Promise<void> =>
|
|
|
40
33
|
requireReplies(REQUIREMENTS)
|
|
41
34
|
} while (await noteGate(REQUIREMENTS, answerProductQuestions))
|
|
42
35
|
})
|
|
43
|
-
|
|
44
|
-
/** Work out the technical plan, then decompose it into package files. */
|
|
45
|
-
export const architecture = (): Promise<void> =>
|
|
46
|
-
scope("architecture", async () => {
|
|
47
|
-
do {
|
|
48
|
-
await author()
|
|
49
|
-
requireReplies(ARCHITECTURE)
|
|
50
|
-
} while (await noteGate(ARCHITECTURE, answerTechnicalQuestions))
|
|
51
|
-
await decompose()
|
|
52
|
-
if (changes(".gtd/packages/**").length === 0) {
|
|
53
|
-
refuse("gtd land: decompose: write at least one package under .gtd/packages/")
|
|
54
|
-
}
|
|
55
|
-
if (changes(ARCHITECTURE).some((c) => c.status === "deleted")) {
|
|
56
|
-
refuse(
|
|
57
|
-
"gtd land: decompose: keep .gtd/ARCHITECTURE.md — the packages are built from it; it is removed with the last package",
|
|
58
|
-
)
|
|
59
|
-
}
|
|
60
|
-
})
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
@inmem
|
|
3
3
|
Feature: a refactor that carried the whole feature still gets a feature review
|
|
4
4
|
|
|
5
|
-
With
|
|
5
|
+
With GTD_FLAG_RISK_TIER off, a refactor-first
|
|
6
6
|
refactor can land everything the requirements ask for. The feature slice's
|
|
7
7
|
implement turn then has nothing to author: its empty turn completes the
|
|
8
8
|
step, and with no code changed since the refactor the feature review covers
|
|
@@ -12,7 +12,6 @@ Feature: a refactor that carried the whole feature still gets a feature review
|
|
|
12
12
|
Given the shipped workflows, as gtd install scaffolds them
|
|
13
13
|
And an environment variable "GTD_QUALITYREVIEWS" set to ""
|
|
14
14
|
And an environment variable "GTD_REFACTORQUALITYREVIEWS" set to ""
|
|
15
|
-
And an environment variable "GTD_FLAG_NAIVE_PASS" set to "1"
|
|
16
15
|
And an environment variable "GTD_FLAG_RISK_TIER" set to "0"
|
|
17
16
|
And a file "src/calc.ts" with:
|
|
18
17
|
"""
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
@inmem
|
|
3
3
|
Feature: a refactor-first judgment walks one fixed path to idle
|
|
4
4
|
|
|
5
|
-
With
|
|
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
7
|
that refactor reviewed, and only then implemented. The flags are
|
|
8
8
|
pinned so the per-flag test runs never move it off its path.
|
|
@@ -11,7 +11,6 @@ Feature: a refactor-first judgment walks one fixed path to idle
|
|
|
11
11
|
Given the shipped workflows, as gtd install scaffolds them
|
|
12
12
|
And an environment variable "GTD_QUALITYREVIEWS" set to ""
|
|
13
13
|
And an environment variable "GTD_REFACTORQUALITYREVIEWS" set to ""
|
|
14
|
-
And an environment variable "GTD_FLAG_NAIVE_PASS" set to "1"
|
|
15
14
|
And an environment variable "GTD_FLAG_RISK_TIER" set to "0"
|
|
16
15
|
And a file "src/calc.ts" with:
|
|
17
16
|
"""
|
|
@@ -154,7 +153,6 @@ Feature: a refactor-first judgment walks one fixed path to idle
|
|
|
154
153
|
gtd(human): build.review.await-review → build.review.closing
|
|
155
154
|
gtd(check): build.review.closing → idle
|
|
156
155
|
"""
|
|
157
|
-
And the commit "gtd(human): idle → unwind" has a body containing "Gtd-Var: flag_naive_pass=1"
|
|
158
156
|
And the commit "gtd(human): idle → unwind" has a body containing "Gtd-Var: flag_risk_tier=0"
|
|
159
157
|
And the commit "gtd(agent): seam.naive → seam.judge" has a body containing "Gtd-Kept:"
|
|
160
158
|
And the commit "gtd(judge): seam.judge → refactor.deriving" has a body containing "\"answer\":\"refactor-first\""
|
|
@@ -10,7 +10,6 @@ Feature: the refactor slice is reviewed on its own before the feature is impleme
|
|
|
10
10
|
Background:
|
|
11
11
|
Given the shipped workflows, as gtd install scaffolds them
|
|
12
12
|
And an environment variable "GTD_QUALITYREVIEWS" set to ""
|
|
13
|
-
And an environment variable "GTD_FLAG_NAIVE_PASS" set to "1"
|
|
14
13
|
And an environment variable "GTD_FLAG_RISK_TIER" set to "0"
|
|
15
14
|
|
|
16
15
|
Scenario: with a narrowed seamAllow a test file added by the refactor is refused
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
@inmem
|
|
2
2
|
Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_TIER
|
|
3
3
|
|
|
4
|
-
With
|
|
4
|
+
With GTD_FLAG_RISK_TIER on, design.triage asks
|
|
5
5
|
for a risk tier and production signals, and the design gate's exit lands them
|
|
6
6
|
as Gtd-Mark trailers: one `risk-tier=<low|high>`, one `production-signal`
|
|
7
7
|
per signal. A missing or unreadable tier is high. With the flag off, nothing
|
|
@@ -10,7 +10,6 @@ Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_T
|
|
|
10
10
|
Background:
|
|
11
11
|
Given the shipped workflows, as gtd install scaffolds them
|
|
12
12
|
And an environment variable "GTD_QUALITYREVIEWS" set to ""
|
|
13
|
-
And an environment variable "GTD_FLAG_NAIVE_PASS" set to "1"
|
|
14
13
|
|
|
15
14
|
Rule: with GTD_FLAG_RISK_TIER on
|
|
16
15
|
|
|
@@ -35,7 +34,7 @@ Feature: the risk tier is proposed at triage and recorded behind GTD_FLAG_RISK_T
|
|
|
35
34
|
And step "unwind" changes nothing
|
|
36
35
|
And step "start-gate.check" changes nothing
|
|
37
36
|
|
|
38
|
-
Scenario: with
|
|
37
|
+
Scenario: with the flag on the triage prompt asks for the tier and the signals
|
|
39
38
|
When the process is driven
|
|
40
39
|
Then the process rests at "design.triage"
|
|
41
40
|
And the resting step's content contains "## Risk Tier"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
@inmem
|
|
3
3
|
Feature: rejected naive passes walk one fixed path through the steer gate to idle
|
|
4
4
|
|
|
5
|
-
With
|
|
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
|
|
7
7
|
steered rerun lands. The flags are pinned so the per-flag test runs never
|
|
8
8
|
move it off its path.
|
|
@@ -10,7 +10,6 @@ Feature: rejected naive passes walk one fixed path through the steer gate to idl
|
|
|
10
10
|
Background:
|
|
11
11
|
Given the shipped workflows, as gtd install scaffolds them
|
|
12
12
|
And an environment variable "GTD_QUALITYREVIEWS" set to ""
|
|
13
|
-
And an environment variable "GTD_FLAG_NAIVE_PASS" set to "1"
|
|
14
13
|
And an environment variable "GTD_FLAG_RISK_TIER" set to "0"
|
|
15
14
|
And a file "src/calc.ts" with:
|
|
16
15
|
"""
|
|
@@ -136,7 +135,6 @@ Feature: rejected naive passes walk one fixed path through the steer gate to idl
|
|
|
136
135
|
gtd(human): build.review.await-review → build.review.closing
|
|
137
136
|
gtd(check): build.review.closing → idle
|
|
138
137
|
"""
|
|
139
|
-
And the commit "gtd(human): idle → unwind" has a body containing "Gtd-Var: flag_naive_pass=1"
|
|
140
138
|
And the commit "gtd(human): idle → unwind" has a body containing "Gtd-Var: flag_risk_tier=0"
|
|
141
139
|
And the commit "gtd(agent): seam.naive → seam.judge" has a body containing "Gtd-Kept:"
|
|
142
140
|
And the commit "gtd(judge): seam.judge → seam.naive" has a body containing "\"answer\":\"reject\""
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
@inmem
|
|
2
|
-
Feature: the naive pass and seam judge
|
|
2
|
+
Feature: the naive pass and seam judge decide how a feature is built
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
off nothing changes: architecture and packages run as before.
|
|
4
|
+
After design a naive pass is set aside under a kept ref, the judge reads its
|
|
5
|
+
diff, and the process either implements straight away, refactors the seam
|
|
6
|
+
first behind a human approval, or retries the naive pass.
|
|
8
7
|
|
|
9
8
|
Background:
|
|
10
9
|
Given the shipped workflows, as gtd install scaffolds them
|
|
@@ -17,7 +16,6 @@ Feature: the naive pass and seam judge replace architecture behind GTD_FLAG_NAIV
|
|
|
17
16
|
}
|
|
18
17
|
"""
|
|
19
18
|
And an environment variable "GTD_QUALITYREVIEWS" set to ""
|
|
20
|
-
And an environment variable "GTD_FLAG_NAIVE_PASS" set to "1"
|
|
21
19
|
And a file "src/calc.ts" with:
|
|
22
20
|
"""
|
|
23
21
|
export const add = (a: number, b: number) => a + b
|
|
@@ -17,6 +17,7 @@ import { coder, FEEDBACK, REQUIREMENTS } from "../shared/steps.js"
|
|
|
17
17
|
import * as t from "../shared/text.js"
|
|
18
18
|
import { defaults } from "../shared/vars.js"
|
|
19
19
|
import { refactorStrays, reviewedRefactor } from "./refactor.js"
|
|
20
|
+
import { flagModeOn } from "../shared/options.js"
|
|
20
21
|
import type { RiskTier } from "./tier.js"
|
|
21
22
|
|
|
22
23
|
/** Naive-pass retries after a `reject`; the next `reject` rests at `seam.steer`. */
|
|
@@ -71,6 +72,7 @@ export function implement(
|
|
|
71
72
|
options.tier,
|
|
72
73
|
options.amend,
|
|
73
74
|
options.afterRefactor,
|
|
75
|
+
flagModeOn(),
|
|
74
76
|
),
|
|
75
77
|
{
|
|
76
78
|
label: "Implementing",
|
|
@@ -21,26 +21,6 @@ describe("the feature workflow's own steps declare skills — a step's rendered
|
|
|
21
21
|
expect(prompt).toContain("spec-driven-development, planning-and-task-breakdown")
|
|
22
22
|
})
|
|
23
23
|
|
|
24
|
-
it("author carries architecture.author's bundled skills", async () => {
|
|
25
|
-
const prompt = agentPrompt(await capture(() => steps.author(), "architecture"))
|
|
26
|
-
expect(prompt).toContain("api-and-interface-design, documentation-and-adrs, ponytail")
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
it("decompose carries architecture.decompose's bundled skills", async () => {
|
|
30
|
-
const prompt = agentPrompt(await capture(() => steps.decompose(), "architecture"))
|
|
31
|
-
expect(prompt).toContain("incremental-implementation, planning-and-task-breakdown")
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
it("build carries packages.item.building's bundled skills", async () => {
|
|
35
|
-
const prompt = agentPrompt(await capture(() => steps.build("pkg"), "packages.item"))
|
|
36
|
-
expect(prompt).toContain("test-driven-development, incremental-implementation")
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
it("fixSuite carries packages.item.fix.suite's bundled skills", async () => {
|
|
40
|
-
const prompt = agentPrompt(await capture(() => steps.fixSuite(), "packages.item"))
|
|
41
|
-
expect(prompt).toContain("debugging-and-error-recovery")
|
|
42
|
-
})
|
|
43
|
-
|
|
44
24
|
it("collecting carries build.review.collecting's bundled skills", async () => {
|
|
45
25
|
const prompt = agentPrompt(await capture(() => steps.collecting("capture"), "build"))
|
|
46
26
|
expect(prompt).toContain("code-review-and-quality")
|
|
@@ -2,15 +2,7 @@ import { human, run, scope, type ScopeAccess } from "../../flows/index.js"
|
|
|
2
2
|
import type { CollectRound } from "../../workflow-kit/index.js"
|
|
3
3
|
import * as t from "../shared/text.js"
|
|
4
4
|
import { riskTierOn } from "./tier.js"
|
|
5
|
-
import {
|
|
6
|
-
ARCHITECTURE,
|
|
7
|
-
coder,
|
|
8
|
-
FEEDBACK,
|
|
9
|
-
planner,
|
|
10
|
-
REFACTOR,
|
|
11
|
-
REQUIREMENTS,
|
|
12
|
-
REVIEW,
|
|
13
|
-
} from "../shared/steps.js"
|
|
5
|
+
import { planner, REFACTOR, REQUIREMENTS, REVIEW } from "../shared/steps.js"
|
|
14
6
|
|
|
15
7
|
/** Turn the sketch since `base` into `.gtd/REQUIREMENTS.md`. */
|
|
16
8
|
export const triage = (base: string): Promise<void> =>
|
|
@@ -22,22 +14,6 @@ export const triage = (base: string): Promise<void> =>
|
|
|
22
14
|
system: t.designSystem(),
|
|
23
15
|
})
|
|
24
16
|
|
|
25
|
-
export const author = (): Promise<void> =>
|
|
26
|
-
t.agentWithSkills("author", t.architectureAuthorPrompt(), {
|
|
27
|
-
label: "Refining the technical plan",
|
|
28
|
-
file: ARCHITECTURE,
|
|
29
|
-
mode: "qa",
|
|
30
|
-
model: planner(),
|
|
31
|
-
system: t.architectSystem(),
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
export const decompose = (): Promise<void> =>
|
|
35
|
-
t.agentWithSkills("decompose.decomposing", t.architectureDecomposePrompt(), {
|
|
36
|
-
label: "Decomposing into packages",
|
|
37
|
-
model: planner(),
|
|
38
|
-
system: t.architectSystem(),
|
|
39
|
-
})
|
|
40
|
-
|
|
41
17
|
export const answerProductQuestions = (): Promise<void> =>
|
|
42
18
|
human("gate.answer", {
|
|
43
19
|
message: t.designGateAnswerMessage(riskTierOn()),
|
|
@@ -47,30 +23,6 @@ export const answerProductQuestions = (): Promise<void> =>
|
|
|
47
23
|
acceptClean: true,
|
|
48
24
|
})
|
|
49
25
|
|
|
50
|
-
export const answerTechnicalQuestions = (): Promise<void> =>
|
|
51
|
-
human("gate.answer", {
|
|
52
|
-
message: t.architectureGateAnswerMessage(),
|
|
53
|
-
label: "Awaiting your technical answers",
|
|
54
|
-
file: ARCHITECTURE,
|
|
55
|
-
mode: "qa",
|
|
56
|
-
acceptClean: true,
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
export const build = (pkg: string): Promise<void> =>
|
|
60
|
-
t.agentWithSkills("building", t.packagesItemBuildingPrompt(pkg), {
|
|
61
|
-
label: "Building",
|
|
62
|
-
model: coder(),
|
|
63
|
-
system: t.builderSystem(),
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
export const fixSuite = (): Promise<void> =>
|
|
67
|
-
t.agentWithSkills("fix.suite.fixing", t.packagesItemFixSuitePrompt(), {
|
|
68
|
-
label: "Fixing the check",
|
|
69
|
-
file: FEEDBACK,
|
|
70
|
-
model: coder(),
|
|
71
|
-
system: t.builderSystem(),
|
|
72
|
-
})
|
|
73
|
-
|
|
74
26
|
/** Answer every `question` note inline in `.gtd/REVIEW.md`. */
|
|
75
27
|
export const answerReviewQuestions = (notes: readonly t.NoteInput[]): Promise<void> =>
|
|
76
28
|
t.agentWithSkills("review.answer-review-questions", t.buildReviewAnswerQuestionsPrompt(notes), {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
@inmem
|
|
2
|
-
Feature: a process keeps the
|
|
2
|
+
Feature: a process keeps the risk tier setting it started with when GTD_FLAG_RISK_TIER changes
|
|
3
3
|
|
|
4
4
|
The flag is recorded in the opening commit, so flipping it mid-process never
|
|
5
|
-
|
|
5
|
+
changes whether the process asks for and records a risk tier.
|
|
6
6
|
|
|
7
7
|
Background:
|
|
8
8
|
Given the shipped workflows, as gtd install scaffolds them
|
|
@@ -29,24 +29,30 @@ Feature: a process keeps the path it started on when GTD_FLAG_NAIVE_PASS changes
|
|
|
29
29
|
### Subtract
|
|
30
30
|
|
|
31
31
|
- `subtract(a, b)` returns `a - b`.
|
|
32
|
+
|
|
33
|
+
## Risk Tier
|
|
34
|
+
|
|
35
|
+
low — a new pure function
|
|
32
36
|
"""
|
|
33
37
|
|
|
34
|
-
Scenario: a process started with the flag off
|
|
35
|
-
Given the ambient environment variable "
|
|
38
|
+
Scenario: a process started with the flag off records no tier after the flag turns on
|
|
39
|
+
Given the ambient environment variable "GTD_FLAG_RISK_TIER" is "0"
|
|
36
40
|
When the process is driven
|
|
37
41
|
Then the process rests at "design.gate.answer"
|
|
38
|
-
Given the ambient environment variable "
|
|
42
|
+
Given the ambient environment variable "GTD_FLAG_RISK_TIER" is "1"
|
|
39
43
|
And step "design.gate.answer" changes nothing
|
|
40
44
|
When the process is driven
|
|
41
|
-
Then the process rests at "
|
|
42
|
-
And the commit "gtd(human): idle → unwind" has a body containing "Gtd-Var:
|
|
45
|
+
Then the process rests at "seam.naive"
|
|
46
|
+
And the commit "gtd(human): idle → unwind" has a body containing "Gtd-Var: flag_risk_tier=0"
|
|
47
|
+
And no commit body contains "Gtd-Mark:"
|
|
43
48
|
|
|
44
|
-
Scenario: a process started with the flag on
|
|
45
|
-
Given the ambient environment variable "
|
|
49
|
+
Scenario: a process started with the flag on records its tier after the flag turns off
|
|
50
|
+
Given the ambient environment variable "GTD_FLAG_RISK_TIER" is "1"
|
|
46
51
|
When the process is driven
|
|
47
52
|
Then the process rests at "design.gate.answer"
|
|
48
|
-
Given the ambient environment variable "
|
|
53
|
+
Given the ambient environment variable "GTD_FLAG_RISK_TIER" is "0"
|
|
49
54
|
And step "design.gate.answer" changes nothing
|
|
50
55
|
When the process is driven
|
|
51
56
|
Then the process rests at "seam.naive"
|
|
52
|
-
And the commit "gtd(human): idle → unwind" has a body containing "Gtd-Var:
|
|
57
|
+
And the commit "gtd(human): idle → unwind" has a body containing "Gtd-Var: flag_risk_tier=1"
|
|
58
|
+
And the last commit body contains "Gtd-Mark: risk-tier=low"
|
|
@@ -9,11 +9,9 @@ const withVars = (vars: Record<string, string>) => installContext(fixtureContext
|
|
|
9
9
|
|
|
10
10
|
describe("riskTierOn", () => {
|
|
11
11
|
it.each([
|
|
12
|
-
[{
|
|
13
|
-
[{
|
|
14
|
-
[{
|
|
15
|
-
[{ flag_naive_pass: "0", flag_risk_tier: "0" }, false],
|
|
16
|
-
[{ flag_naive_pass: "1" }, false],
|
|
12
|
+
[{ flag_risk_tier: "1" }, true],
|
|
13
|
+
[{ flag_risk_tier: "0" }, false],
|
|
14
|
+
[{}, false],
|
|
17
15
|
])("%j is %s", (vars, expected) => {
|
|
18
16
|
withVars(vars)
|
|
19
17
|
expect(riskTierOn()).toBe(expected)
|
|
@@ -4,8 +4,8 @@ import { REQUIREMENTS } from "../shared/steps.js"
|
|
|
4
4
|
|
|
5
5
|
export type RiskTier = "low" | "high"
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
export const riskTierOn = (): boolean => vars.
|
|
7
|
+
/** GTD_FLAG_RISK_TIER: pinned at process start, so a mid-process flip never moves a process. */
|
|
8
|
+
export const riskTierOn = (): boolean => vars.flag_risk_tier === "1"
|
|
9
9
|
|
|
10
10
|
const sectionLines = (
|
|
11
11
|
text: string | undefined,
|
package/src/workflows/index.ts
CHANGED
|
@@ -22,7 +22,6 @@ export {
|
|
|
22
22
|
export { lensesOf } from "../workflow-kit/index.js"
|
|
23
23
|
export * from "./feature/steps.js"
|
|
24
24
|
export * from "./feature/planning.js"
|
|
25
|
-
export * from "./feature/packages.js"
|
|
26
25
|
export * from "./feature/refactor.js"
|
|
27
26
|
export * from "./feature/seam.js"
|
|
28
27
|
export {
|
|
@@ -10,8 +10,6 @@ describe("the bundled workflow's access export", () => {
|
|
|
10
10
|
it("restricts writes on planning, review and lens scopes only", () => {
|
|
11
11
|
expect(bundled).toEqual({
|
|
12
12
|
design: { write: [] },
|
|
13
|
-
architecture: { write: [".gtd/REQUIREMENTS.md"] },
|
|
14
|
-
"architecture.decompose": { write: [".gtd/packages/**", ".gtd/ARCHITECTURE.md"] },
|
|
15
13
|
"build.review": { write: [".gtd/REVIEW.md"] },
|
|
16
14
|
"build.review.defer": { write: [".gtd/TODO.md"] },
|
|
17
15
|
"build.review.fix.nits": {},
|
|
@@ -12,8 +12,6 @@ export const access = (
|
|
|
12
12
|
vars: Readonly<Record<string, string>>,
|
|
13
13
|
): Readonly<Record<string, ScopeAccess>> => ({
|
|
14
14
|
design: { write: [] },
|
|
15
|
-
architecture: { write: [".gtd/REQUIREMENTS.md"] },
|
|
16
|
-
"architecture.decompose": { write: [".gtd/packages/**", ".gtd/ARCHITECTURE.md"] },
|
|
17
15
|
"build.review": { write: [".gtd/REVIEW.md"] },
|
|
18
16
|
"build.review.defer": { write: [".gtd/TODO.md"] },
|
|
19
17
|
// `{}` reopens what `build.review` restricted: the fixes edit code.
|
|
@@ -23,11 +23,22 @@ describe("the shipped workflow factories", () => {
|
|
|
23
23
|
expect(defaults).toHaveProperty(`flag_${name}`, defaultOn ? "1" : "0")
|
|
24
24
|
})
|
|
25
25
|
|
|
26
|
-
it("declare seamAllow
|
|
27
|
-
expect(Object.keys(ShippedOptions.fields)).not.toContain("flag_naive_pass")
|
|
26
|
+
it("declare a seamAllow default a factory option overrides", () => {
|
|
28
27
|
expect(configure(feature({ seamAllow: "docs/**" }))).toMatchObject({
|
|
29
28
|
ok: true,
|
|
30
|
-
build: { defaults: { seamAllow: "docs/**"
|
|
29
|
+
build: { defaults: { seamAllow: "docs/**" } },
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it("default flagMode on and lay a boolean factory option over it as a string", () => {
|
|
34
|
+
expect(defaults.flagMode).toBe("true")
|
|
35
|
+
expect(configure(feature({ flagMode: false }))).toMatchObject({
|
|
36
|
+
ok: true,
|
|
37
|
+
build: { defaults: { flagMode: "false" } },
|
|
38
|
+
})
|
|
39
|
+
expect(configure(review({ flagMode: true }))).toMatchObject({
|
|
40
|
+
ok: true,
|
|
41
|
+
build: { defaults: { flagMode: "true" } },
|
|
31
42
|
})
|
|
32
43
|
})
|
|
33
44
|
|