@pmelab/gtd 56.0.0 → 58.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 +29 -35
- package/dist/chunks/{reserved-B8EC-WE8.mjs → reserved-BzAFXuz_.mjs} +56 -131
- package/dist/chunks/{review-HdrX0FJ7.mjs → review-CVqRS0mc.mjs} +2 -2
- package/dist/chunks/{tail-BSLah2mA.mjs → tail-JQzB21Q3.mjs} +1 -1
- package/dist/workflows/cleanup.mjs +2 -2
- package/dist/workflows/feature.mjs +99 -170
- package/dist/workflows/fix.mjs +2 -2
- package/dist/workflows/review.mjs +3 -3
- package/dist/workflows/rollout.mjs +1 -1
- package/dist/workflows.mjs +150 -297
- package/package.json +1 -1
- package/src/workflows/feature/acceptance-criteria.feature +32 -0
- package/src/workflows/feature/criteria-coverage.feature +0 -2
- package/src/workflows/feature/criteria.test.ts +1 -41
- package/src/workflows/feature/criteria.ts +12 -18
- package/src/workflows/feature/fast-path.feature +4 -1
- package/src/workflows/feature/feature.test.ts +3 -39
- package/src/workflows/feature/feature.ts +6 -8
- package/src/workflows/feature/lens-models.feature +0 -2
- package/src/workflows/feature/lens-review.feature +0 -2
- package/src/workflows/feature/naive-acceptance.feature +4 -0
- package/src/workflows/feature/naive-test.feature +263 -0
- package/src/workflows/feature/one-step-land.feature +4 -1
- package/src/workflows/feature/planning.ts +2 -0
- package/src/workflows/feature/refactor-absorbs.feature +4 -1
- package/src/workflows/feature/refactor-first.feature +4 -1
- package/src/workflows/feature/refactor-lens-models.feature +4 -0
- package/src/workflows/feature/refactor-rebuild.feature +4 -1
- package/src/workflows/feature/refactor-review.feature +20 -1
- package/src/workflows/feature/release-flag.feature +167 -0
- package/src/workflows/feature/release-flag.test.ts +49 -0
- package/src/workflows/feature/release-flag.ts +46 -0
- package/src/workflows/feature/review-gate.feature +1 -3
- package/src/workflows/feature/reviewer-walkthrough.feature +0 -2
- package/src/workflows/feature/risk-tier.feature +32 -0
- package/src/workflows/feature/seam-rejection.feature +8 -1
- package/src/workflows/feature/seam.feature +8 -1
- package/src/workflows/feature/seam.test.ts +21 -9
- package/src/workflows/feature/seam.ts +60 -14
- package/src/workflows/feature/standards.feature +0 -2
- package/src/workflows/shared/options.test.ts +3 -10
- package/src/workflows/shared/options.ts +5 -6
- package/src/workflows/shared/prose.ts +0 -6
- package/src/workflows/shared/skills.test.ts +0 -4
- package/src/workflows/shared/skills.ts +0 -5
- package/src/workflows/shared/steps.ts +1 -1
- package/src/workflows/shared/text.test.ts +58 -69
- package/src/workflows/shared/text.ts +79 -162
- package/src/workflows/shared/vars.ts +2 -4
- package/src/workflows/feature/flag-mode.feature +0 -88
- package/src/workflows/feature/hands-on-skip.feature +0 -316
- package/src/workflows/feature/prototype-rounds.feature +0 -156
- package/src/workflows/feature/prototype.feature +0 -428
- package/src/workflows/feature/prototype.test.ts +0 -43
- package/src/workflows/feature/prototype.ts +0 -198
package/package.json
CHANGED
|
@@ -39,6 +39,10 @@ Feature: acceptance criteria carry stable IDs, and a sketch that states clear on
|
|
|
39
39
|
|
|
40
40
|
- the greeting module
|
|
41
41
|
|
|
42
|
+
## Release Flag
|
|
43
|
+
|
|
44
|
+
new
|
|
45
|
+
|
|
42
46
|
## Acceptance Criteria
|
|
43
47
|
|
|
44
48
|
- AC-1: `greeting` reads "Hello, world".
|
|
@@ -67,6 +71,10 @@ Feature: acceptance criteria carry stable IDs, and a sketch that states clear on
|
|
|
67
71
|
|
|
68
72
|
- the greeting module
|
|
69
73
|
|
|
74
|
+
## Release Flag
|
|
75
|
+
|
|
76
|
+
new
|
|
77
|
+
|
|
70
78
|
## Acceptance Criteria
|
|
71
79
|
|
|
72
80
|
- `greeting` reads "Hello, world".
|
|
@@ -82,6 +90,10 @@ Feature: acceptance criteria carry stable IDs, and a sketch that states clear on
|
|
|
82
90
|
|
|
83
91
|
- the greeting module
|
|
84
92
|
|
|
93
|
+
## Release Flag
|
|
94
|
+
|
|
95
|
+
new
|
|
96
|
+
|
|
85
97
|
## Acceptance Criteria
|
|
86
98
|
|
|
87
99
|
- AC-1: `greeting` reads "Hello, world".
|
|
@@ -98,6 +110,10 @@ Feature: acceptance criteria carry stable IDs, and a sketch that states clear on
|
|
|
98
110
|
|
|
99
111
|
- the greeting module
|
|
100
112
|
|
|
113
|
+
## Release Flag
|
|
114
|
+
|
|
115
|
+
new
|
|
116
|
+
|
|
101
117
|
## Acceptance Criteria
|
|
102
118
|
|
|
103
119
|
- AC-1: `greeting` reads "Hello, world".
|
|
@@ -131,6 +147,10 @@ Feature: acceptance criteria carry stable IDs, and a sketch that states clear on
|
|
|
131
147
|
|
|
132
148
|
- the greeting module
|
|
133
149
|
|
|
150
|
+
## Release Flag
|
|
151
|
+
|
|
152
|
+
new
|
|
153
|
+
|
|
134
154
|
## Acceptance Criteria
|
|
135
155
|
|
|
136
156
|
- AC-1: `greeting` reads "Hi".
|
|
@@ -150,6 +170,10 @@ Feature: acceptance criteria carry stable IDs, and a sketch that states clear on
|
|
|
150
170
|
"""
|
|
151
171
|
# Requirements
|
|
152
172
|
|
|
173
|
+
## Release Flag
|
|
174
|
+
|
|
175
|
+
new
|
|
176
|
+
|
|
153
177
|
## Acceptance Criteria
|
|
154
178
|
|
|
155
179
|
- AC-1: `greeting` reads "Hello, world".
|
|
@@ -178,6 +202,10 @@ Feature: acceptance criteria carry stable IDs, and a sketch that states clear on
|
|
|
178
202
|
|
|
179
203
|
- the greeting module
|
|
180
204
|
|
|
205
|
+
## Release Flag
|
|
206
|
+
|
|
207
|
+
new
|
|
208
|
+
|
|
181
209
|
## Acceptance Criteria
|
|
182
210
|
|
|
183
211
|
- AC-1: `greeting` reads "Hi".
|
|
@@ -226,6 +254,10 @@ Feature: acceptance criteria carry stable IDs, and a sketch that states clear on
|
|
|
226
254
|
|
|
227
255
|
- the greeting module
|
|
228
256
|
|
|
257
|
+
## Release Flag
|
|
258
|
+
|
|
259
|
+
new
|
|
260
|
+
|
|
229
261
|
## Acceptance Criteria
|
|
230
262
|
|
|
231
263
|
- AC-1: `greeting` reads "Hello, world".
|
|
@@ -7,9 +7,7 @@ Feature: the criteria-coverage lens checks the change's tests against its criter
|
|
|
7
7
|
|
|
8
8
|
Background:
|
|
9
9
|
Given the shipped workflows, as gtd install scaffolds them
|
|
10
|
-
And an environment variable "GTD_PROTOTYPEROUNDS" set to "0"
|
|
11
10
|
And an environment variable "GTD_QUALITYREVIEWS" set to "criteria-coverage"
|
|
12
|
-
And an environment variable "GTD_FLAGMODE" set to "false"
|
|
13
11
|
And a file "src/calc.ts" with:
|
|
14
12
|
"""
|
|
15
13
|
export const add = (a: number, b: number) => a + b
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest"
|
|
2
2
|
import type { Change } from "../../flows/index.js"
|
|
3
|
-
import {
|
|
4
|
-
criteriaOf,
|
|
5
|
-
criterionIds,
|
|
6
|
-
handsOnIds,
|
|
7
|
-
hasImpact,
|
|
8
|
-
statedCriteria,
|
|
9
|
-
unstableIds,
|
|
10
|
-
} from "./criteria.js"
|
|
3
|
+
import { criteriaOf, criterionIds, hasImpact, statedCriteria, unstableIds } from "./criteria.js"
|
|
11
4
|
|
|
12
5
|
const added = (path: string, after: string): Change => ({
|
|
13
6
|
path,
|
|
@@ -55,17 +48,6 @@ describe("criteriaOf", () => {
|
|
|
55
48
|
).toEqual([{ id: "AC-1", text: "exits 2 when config is bad - missing file" }])
|
|
56
49
|
})
|
|
57
50
|
|
|
58
|
-
it("reads the (no hands-on) tag between an ID and its colon", () => {
|
|
59
|
-
expect(
|
|
60
|
-
criteriaOf(
|
|
61
|
-
"## Acceptance Criteria\n\n- AC-1: runs\n- AC-2 (no hands-on): the prompt says so\n",
|
|
62
|
-
),
|
|
63
|
-
).toEqual([
|
|
64
|
-
{ id: "AC-1", text: "runs" },
|
|
65
|
-
{ id: "AC-2", text: "the prompt says so", noHandsOn: true },
|
|
66
|
-
])
|
|
67
|
-
})
|
|
68
|
-
|
|
69
51
|
it("is undefined without the section", () => {
|
|
70
52
|
expect(criteriaOf("# R\n\n- AC-1: x\n")).toBeUndefined()
|
|
71
53
|
})
|
|
@@ -84,19 +66,6 @@ describe("statedCriteria", () => {
|
|
|
84
66
|
})
|
|
85
67
|
})
|
|
86
68
|
|
|
87
|
-
it("keeps a stated (no hands-on) tag, renumbered or not", () => {
|
|
88
|
-
const tagged = "## Acceptance criteria\n\n- AC-1: a\n- AC-2 (no hands-on): b\n"
|
|
89
|
-
expect(statedCriteria([added("TODO.md", tagged)], "abc")?.criteria).toEqual([
|
|
90
|
-
{ id: "AC-1", text: "a" },
|
|
91
|
-
{ id: "AC-2", text: "b", noHandsOn: true },
|
|
92
|
-
])
|
|
93
|
-
const partial = "## Acceptance criteria\n\n- a\n- AC-7 (no hands-on): b\n"
|
|
94
|
-
expect(statedCriteria([added("TODO.md", partial)], "abc")?.criteria).toEqual([
|
|
95
|
-
{ id: "AC-1", text: "a" },
|
|
96
|
-
{ id: "AC-2", text: "b", noHandsOn: true },
|
|
97
|
-
])
|
|
98
|
-
})
|
|
99
|
-
|
|
100
69
|
it("renumbers when the stated IDs are partial or clash", () => {
|
|
101
70
|
const sketch = [added("TODO.md", "## Acceptance criteria\n\n- AC-4: a\n- b\n")]
|
|
102
71
|
expect(statedCriteria(sketch, "abc")?.criteria).toEqual([
|
|
@@ -144,15 +113,6 @@ describe("criterionIds", () => {
|
|
|
144
113
|
})
|
|
145
114
|
})
|
|
146
115
|
|
|
147
|
-
describe("handsOnIds", () => {
|
|
148
|
-
const requirements =
|
|
149
|
-
"## Acceptance Criteria\n\n- AC-1: a\n- AC-2 (no hands-on): b\n- AC-3: c\n- AC-4 (no hands-on): d\n"
|
|
150
|
-
|
|
151
|
-
it("leaves out every criterion tagged (no hands-on)", () => {
|
|
152
|
-
expect(handsOnIds(requirements)).toEqual(["AC-1", "AC-3"])
|
|
153
|
-
})
|
|
154
|
-
})
|
|
155
|
-
|
|
156
116
|
describe("unstableIds", () => {
|
|
157
117
|
const ids = { closed: ["AC-1", "AC-3"], used: ["AC-1", "AC-2", "AC-3"] }
|
|
158
118
|
|
|
@@ -13,12 +13,11 @@ import {
|
|
|
13
13
|
import { HEADING, ITEM, markFenced } from "../shared/fences.js"
|
|
14
14
|
import { planner, REQUIREMENTS } from "../shared/steps.js"
|
|
15
15
|
import * as t from "../shared/text.js"
|
|
16
|
+
import { requireReleaseFlag } from "./release-flag.js"
|
|
16
17
|
|
|
17
18
|
export interface Criterion {
|
|
18
19
|
readonly id: string
|
|
19
20
|
readonly text: string
|
|
20
|
-
/** Tagged `(no hands-on)`: its tests prove it, so the hands-on test skips it. */
|
|
21
|
-
readonly noHandsOn?: true
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
/** Acceptance criteria the human's sketch stated outright, ready to normalise. */
|
|
@@ -33,13 +32,9 @@ export interface StatedCriteria {
|
|
|
33
32
|
/** Below this the judge's `yes` is not trusted: a wrong skip builds against criteria nobody can check. */
|
|
34
33
|
const CLEAR_MIN_P = 0.8
|
|
35
34
|
|
|
36
|
-
const ID = /^(AC-\d+)
|
|
35
|
+
const ID = /^(AC-\d+):\s*(.*)$/
|
|
37
36
|
|
|
38
|
-
const criterion = (id: RegExpExecArray, as = id[1]!): Criterion => ({
|
|
39
|
-
id: as,
|
|
40
|
-
text: id[3]!,
|
|
41
|
-
...(id[2] === undefined ? {} : { noHandsOn: true }),
|
|
42
|
-
})
|
|
37
|
+
const criterion = (id: RegExpExecArray, as = id[1]!): Criterion => ({ id: as, text: id[2]! })
|
|
43
38
|
|
|
44
39
|
/** The list items under the first heading `title` matches (at `level` when given), up to the next heading; wrapped lines joined, fenced lines ignored. */
|
|
45
40
|
const listUnder = (text: string, title: RegExp, level?: number): string[] | undefined => {
|
|
@@ -83,12 +78,6 @@ export const criteriaOf = (text: string): readonly Criterion[] | undefined =>
|
|
|
83
78
|
export const criterionIds = (text: string): string[] =>
|
|
84
79
|
(criteriaOf(text) ?? []).map((c) => c.id).filter((id) => id !== "")
|
|
85
80
|
|
|
86
|
-
/** The ID'd criteria of `text` a person can try by hand: none tagged `(no hands-on)`. */
|
|
87
|
-
export const handsOnIds = (text: string): string[] => {
|
|
88
|
-
const tagged = (criteriaOf(text) ?? []).filter((c) => c.noHandsOn).map((c) => c.id)
|
|
89
|
-
return criterionIds(text).filter((id) => !tagged.includes(id))
|
|
90
|
-
}
|
|
91
|
-
|
|
92
81
|
/** Items numbered `AC-1`…, unless every one already carries its own distinct ID. */
|
|
93
82
|
const numbered = (items: readonly string[]): Criterion[] => {
|
|
94
83
|
const ids = items.map((item) => ID.exec(item))
|
|
@@ -149,16 +138,20 @@ export const requireCriteria = (file: string): void => {
|
|
|
149
138
|
const isImpactHeading = (h: RegExpExecArray | null): boolean =>
|
|
150
139
|
h !== null && h[1]!.length === 2 && /^impact$/i.test(h[2]!.trim())
|
|
151
140
|
|
|
141
|
+
// The skip path's impact turn may write both: a sketch can ask for a flag.
|
|
142
|
+
const isImpactTurnHeading = (h: RegExpExecArray | null): boolean =>
|
|
143
|
+
h !== null && h[1]!.length === 2 && /^(impact|release flag)$/i.test(h[2]!.trim())
|
|
144
|
+
|
|
152
145
|
/** Whether `text` has an unfenced, level-2 `## Impact` heading. */
|
|
153
146
|
export const hasImpact = (text: string): boolean =>
|
|
154
147
|
markFenced(text).some((l) => !l.fenced && isImpactHeading(HEADING.exec(l.line)))
|
|
155
148
|
|
|
156
|
-
/** `text` without its `## Impact`
|
|
149
|
+
/** `text` without its `## Impact` and `## Release Flag` sections, whitespace collapsed. */
|
|
157
150
|
const withoutImpact = (text: string): string => {
|
|
158
151
|
let inImpact = false
|
|
159
152
|
const kept = markFenced(text).filter((l) => {
|
|
160
153
|
const h = l.fenced ? null : HEADING.exec(l.line)
|
|
161
|
-
if (h !== null && h[1]!.length <= 2) inImpact =
|
|
154
|
+
if (h !== null && h[1]!.length <= 2) inImpact = isImpactTurnHeading(h)
|
|
162
155
|
return !inImpact
|
|
163
156
|
})
|
|
164
157
|
return kept
|
|
@@ -184,13 +177,13 @@ export const requireImpact = (file: string): void => {
|
|
|
184
177
|
)
|
|
185
178
|
}
|
|
186
179
|
|
|
187
|
-
/** Refuse a turn that changed `file` beyond its `## Impact`
|
|
180
|
+
/** Refuse a turn that changed `file` beyond its `## Impact` and `## Release Flag` sections. */
|
|
188
181
|
export const requireImpactOnly = (file: string): void => {
|
|
189
182
|
const change = changes().get(file)
|
|
190
183
|
if (change === undefined) return
|
|
191
184
|
if (withoutImpact(change.before ?? "") === withoutImpact(change.after ?? "")) return
|
|
192
185
|
refuse(
|
|
193
|
-
`gtd land: impact-only: this turn may only add "## Impact" to ${file} — restore everything else`,
|
|
186
|
+
`gtd land: impact-only: this turn may only add "## Impact" (and "## Release Flag") to ${file} — restore everything else`,
|
|
194
187
|
)
|
|
195
188
|
}
|
|
196
189
|
|
|
@@ -252,6 +245,7 @@ const impact = async (): Promise<void> => {
|
|
|
252
245
|
requireCriteriaFrozen(REQUIREMENTS)
|
|
253
246
|
requireImpact(REQUIREMENTS)
|
|
254
247
|
requireImpactOnly(REQUIREMENTS)
|
|
248
|
+
requireReleaseFlag(REQUIREMENTS)
|
|
255
249
|
}
|
|
256
250
|
|
|
257
251
|
/**
|
|
@@ -8,7 +8,6 @@ Feature: a trivial change takes the same few beats at either risk tier
|
|
|
8
8
|
|
|
9
9
|
Background:
|
|
10
10
|
Given the shipped workflows, as gtd install scaffolds them
|
|
11
|
-
And an environment variable "GTD_PROTOTYPEROUNDS" set to "0"
|
|
12
11
|
And an environment variable "GTD_QUALITYREVIEWS" set to "correctness"
|
|
13
12
|
And an environment variable "GTD_FLAG_RISK_TIER" set to "1"
|
|
14
13
|
And a file "src/greeting.ts" with:
|
|
@@ -42,6 +41,10 @@ Feature: a trivial change takes the same few beats at either risk tier
|
|
|
42
41
|
|
|
43
42
|
- the greeting module
|
|
44
43
|
|
|
44
|
+
## Release Flag
|
|
45
|
+
|
|
46
|
+
new
|
|
47
|
+
|
|
45
48
|
## Acceptance Criteria
|
|
46
49
|
|
|
47
50
|
- AC-1: the change behaves as described.
|
|
@@ -302,38 +302,9 @@ describe("an in-flight process from before the architecture path was removed", (
|
|
|
302
302
|
})
|
|
303
303
|
})
|
|
304
304
|
|
|
305
|
-
describe("
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
'import { feature } from "@pmelab/gtd/workflows/feature"',
|
|
309
|
-
'export { summary, steering, skills, access } from "@pmelab/gtd/workflows/feature"',
|
|
310
|
-
`export default ${workflow}`,
|
|
311
|
-
"",
|
|
312
|
-
].join("\n")
|
|
313
|
-
|
|
314
|
-
const designed = async (workflow: string, env: Record<string, string> = {}) => {
|
|
315
|
-
const repo = testRepo({ workflow, env: { GTD_QUALITYREVIEWS: "", ...env } })
|
|
316
|
-
repo.write("src/calc.ts", CALC)
|
|
317
|
-
repo.commit("feat: add calculator")
|
|
318
|
-
repo.write("TODO.md", "# Add subtract\n")
|
|
319
|
-
return repo.drive({
|
|
320
|
-
unwind: () => undefined,
|
|
321
|
-
"start-gate.check": () => undefined,
|
|
322
|
-
"design.triage": (_, r) =>
|
|
323
|
-
r.write(
|
|
324
|
-
".gtd/REQUIREMENTS.md",
|
|
325
|
-
"# Requirements\n\n## Concerns\n\n### S\n\n- `s`\n\n## Impact\n\n- the module\n\n## Acceptance Criteria\n\n- AC-1: done\n",
|
|
326
|
-
),
|
|
327
|
-
"design.gate.answer": () => undefined,
|
|
328
|
-
})
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
it("set on explicitly, runs the naive pass like the default", async () => {
|
|
332
|
-
expect((await designed(config("feature({ flagMode: true })"))).state).toBe("seam.naive")
|
|
333
|
-
})
|
|
334
|
-
|
|
335
|
-
it("off through GTD_FLAGMODE=false, lands the naive pass with no seam judge", async () => {
|
|
336
|
-
const repo = testRepo({ workflow: CONFIG_SCAFFOLD, env: { GTD_FLAGMODE: "false" } })
|
|
305
|
+
describe("release flag", () => {
|
|
306
|
+
it("with no Release Flag section, lands the naive pass with no seam judge", async () => {
|
|
307
|
+
const repo = testRepo({ workflow: CONFIG_SCAFFOLD })
|
|
337
308
|
repo.write("src/calc.ts", CALC)
|
|
338
309
|
repo.commit("feat: add calculator")
|
|
339
310
|
repo.write("TODO.md", "# Add subtract\n")
|
|
@@ -357,13 +328,6 @@ describe("flagMode", () => {
|
|
|
357
328
|
expect(repo.read("src/calc.ts")).toBe(`${CALC}// naive\n`)
|
|
358
329
|
expect(repo.subjects().some((subject) => subject.includes("seam.judge"))).toBe(false)
|
|
359
330
|
})
|
|
360
|
-
|
|
361
|
-
it("refuses a value other than true or false before the process starts", async () => {
|
|
362
|
-
const repo = testRepo({ workflow: CONFIG_SCAFFOLD, env: { GTD_FLAGMODE: "off" } })
|
|
363
|
-
repo.write("TODO.md", "# Add subtract\n")
|
|
364
|
-
await expect(repo.drive({})).rejects.toThrow('flagMode must be "true" or "false", got "off"')
|
|
365
|
-
expect(repo.subjects()).toEqual(["chore: initial commit"])
|
|
366
|
-
})
|
|
367
331
|
})
|
|
368
332
|
|
|
369
333
|
// pins the public re-exports from the feature entry point
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
start,
|
|
10
10
|
} from "../../flows/index.js"
|
|
11
11
|
import { gate } from "../shared/health.js"
|
|
12
|
-
import {
|
|
12
|
+
import { naiveTestOn, shipped } from "../shared/options.js"
|
|
13
13
|
import { FEEDBACK, REQUIREMENTS } from "../shared/steps.js"
|
|
14
14
|
import { refusePendingHandOff } from "../shared/tail.js"
|
|
15
15
|
import * as t from "../shared/text.js"
|
|
@@ -23,16 +23,15 @@ import {
|
|
|
23
23
|
} from "./criteria.js"
|
|
24
24
|
import { design } from "./planning.js"
|
|
25
25
|
import { buildTail, isCode, reUnwind, type ReviewOutcome } from "../shared/review.js"
|
|
26
|
-
import { prototypeRounds } from "./prototype.js"
|
|
27
26
|
import { implement, implementing, seamBuild } from "./seam.js"
|
|
28
27
|
import { recordRisk, riskTierOn } from "./tier.js"
|
|
29
28
|
|
|
30
29
|
// The ordinary start. Any change to the tree starts a process: `idle` →
|
|
31
30
|
// `unwind` reverts the sketch (its intent survives in history) → a
|
|
32
|
-
// green-baseline gate → design → a naive pass,
|
|
31
|
+
// green-baseline gate → design → a naive pass, tried by a person with
|
|
32
|
+
// `naiveTest` on and judged when the requirements ask for a release flag: it
|
|
33
33
|
// lands as the implementation, or (refactoring first when the judge asks) is
|
|
34
|
-
// built fresh from → the health loop →
|
|
35
|
-
// fixed and re-tested → the triaged quality lap and its finding gate → a
|
|
34
|
+
// built fresh from → the health loop → the triaged quality lap and its finding gate → a
|
|
36
35
|
// reviewer's walkthrough of the whole change for the human, which signs off
|
|
37
36
|
// (the episode ends back at `idle`) or sends a design → implement lap.
|
|
38
37
|
|
|
@@ -47,7 +46,7 @@ export const unwind = (): Promise<void> => {
|
|
|
47
46
|
export { reUnwind }
|
|
48
47
|
|
|
49
48
|
/**
|
|
50
|
-
* A naive pass (judged only
|
|
49
|
+
* A naive pass (judged only when a release flag is asked for), then implement and the
|
|
51
50
|
* quality lap, then the review; design must have run since `firstBase`.
|
|
52
51
|
*/
|
|
53
52
|
export const buildFeature = async (firstBase: string): Promise<void> => {
|
|
@@ -140,8 +139,7 @@ export const ordinaryStart = async (): Promise<void> => {
|
|
|
140
139
|
await human("idle", { message: t.idleMessage(), label: "Idle", file: ".gtd/TODO.md" })
|
|
141
140
|
refusePendingHandOff()
|
|
142
141
|
// Read right after idle, so a bad value refuses the landing that would pin it.
|
|
143
|
-
|
|
144
|
-
prototypeRounds()
|
|
142
|
+
naiveTestOn()
|
|
145
143
|
const stated = statedCriteria(changes(), head())
|
|
146
144
|
await unwind()
|
|
147
145
|
if (changes(FEEDBACK).some((c) => c.status !== "deleted")) {
|
|
@@ -11,8 +11,6 @@ Feature: each quality lens runs on its own model hint
|
|
|
11
11
|
import { feature } from "@pmelab/gtd/workflows/feature"
|
|
12
12
|
export { summary, steering, skills, access } from "@pmelab/gtd/workflows/feature"
|
|
13
13
|
export default feature({
|
|
14
|
-
flagMode: false,
|
|
15
|
-
prototypeRounds: "0",
|
|
16
14
|
qualityReviews: "correctness, conventions, test-audit=opus",
|
|
17
15
|
})
|
|
18
16
|
"""
|
|
@@ -11,9 +11,7 @@ Feature: the quality lap's findings are triaged, then decided at the finding gat
|
|
|
11
11
|
|
|
12
12
|
Background:
|
|
13
13
|
Given the shipped workflows, as gtd install scaffolds them
|
|
14
|
-
And an environment variable "GTD_PROTOTYPEROUNDS" set to "0"
|
|
15
14
|
And an environment variable "GTD_QUALITYREVIEWS" set to "correctness"
|
|
16
|
-
And an environment variable "GTD_FLAGMODE" set to "false"
|
|
17
15
|
And a file "src/calc.ts" with:
|
|
18
16
|
"""
|
|
19
17
|
export const add = (a: number, b: number) => a + b
|