@pmelab/gtd 58.2.0 → 59.0.1

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.
Files changed (150) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +120 -395
  3. package/dist/chunks/{Schema-B3o6eRNU.mjs → testkit-07Z_ENch.mjs} +13503 -3460
  4. package/dist/chunks/{wire-C12dahrH.mjs → wire-BTUhRGXj.mjs} +1 -1
  5. package/dist/flows.mjs +1 -1
  6. package/dist/gtd.bundle.mjs +484 -497
  7. package/dist/testkit/gherkin.mjs +145 -65
  8. package/dist/testkit.mjs +1 -1
  9. package/dist/wire.mjs +1 -1
  10. package/package.json +3 -42
  11. package/skills/authoring/SKILL.md +34 -27
  12. package/src/cli/Cli.test.ts +148 -71
  13. package/src/cli/Cli.ts +384 -463
  14. package/src/cli/Help.test.ts +47 -0
  15. package/src/cli/Help.ts +70 -0
  16. package/src/cli/Program.test.ts +127 -33
  17. package/src/cli/Program.ts +70 -25
  18. package/src/edge/Edge.ts +4 -4
  19. package/src/emit/Emit.test.ts +1 -1
  20. package/src/emit/Emit.ts +1 -1
  21. package/src/flags/index.test.ts +0 -13
  22. package/src/flags/index.ts +1 -3
  23. package/src/flows/factory.ts +3 -1
  24. package/src/gherkin/index.ts +135 -71
  25. package/src/gherkin/messages.test.ts +90 -0
  26. package/src/gherkin/messages.ts +84 -0
  27. package/src/install/Install.test.ts +14 -11
  28. package/src/install/Install.ts +38 -15
  29. package/src/install/index.ts +1 -2
  30. package/src/replay/Replay.test.ts +1 -1
  31. package/src/replay/index.ts +1 -1
  32. package/src/step/planStart.ts +6 -1
  33. package/src/testkit/TestRepo.test.ts +47 -2
  34. package/src/testkit/TestRepo.ts +51 -6
  35. package/src/twins/EmittedScriptRecognizer.ts +5 -8
  36. package/src/twins/FlowScripts.ts +1 -1
  37. package/src/wire/Land.ts +1 -1
  38. package/src/workflow/index.ts +1 -0
  39. package/src/workflow/load.test.ts +138 -113
  40. package/src/workflow/load.ts +7 -7
  41. package/src/workflow/skills.test.ts +5 -5
  42. package/src/workflow/skills.ts +1 -1
  43. package/src/workflow/vars.test.ts +30 -3
  44. package/src/workflow/vars.ts +34 -2
  45. package/src/workflow-kit/index.ts +1 -1
  46. package/dist/chunks/reserved-lMYCaapY.mjs +0 -1990
  47. package/dist/chunks/review-Bfaror38.mjs +0 -427
  48. package/dist/chunks/tail-Bd7L940p.mjs +0 -355
  49. package/dist/chunks/testkit-JDtpNKyi.mjs +0 -10410
  50. package/dist/workflows/cleanup.mjs +0 -36
  51. package/dist/workflows/feature.mjs +0 -1018
  52. package/dist/workflows/fix.mjs +0 -41
  53. package/dist/workflows/review.mjs +0 -45
  54. package/dist/workflows/rollout.mjs +0 -48
  55. package/dist/workflows.mjs +0 -40651
  56. package/src/install/ConfigScaffold.ts +0 -22
  57. package/src/workflows/cleanup/cleanup-path.feature +0 -94
  58. package/src/workflows/cleanup/cleanup.feature +0 -315
  59. package/src/workflows/cleanup/cleanup.test.ts +0 -276
  60. package/src/workflows/cleanup/cleanup.ts +0 -52
  61. package/src/workflows/cleanup/index.ts +0 -6
  62. package/src/workflows/feature/acceptance-criteria-tier.feature +0 -25
  63. package/src/workflows/feature/acceptance-criteria.feature +0 -389
  64. package/src/workflows/feature/criteria-coverage.feature +0 -102
  65. package/src/workflows/feature/criteria.test.ts +0 -147
  66. package/src/workflows/feature/criteria.ts +0 -267
  67. package/src/workflows/feature/fast-path.feature +0 -93
  68. package/src/workflows/feature/feature.test.ts +0 -338
  69. package/src/workflows/feature/feature.ts +0 -156
  70. package/src/workflows/feature/green.ts +0 -19
  71. package/src/workflows/feature/index.ts +0 -18
  72. package/src/workflows/feature/lens-models.feature +0 -69
  73. package/src/workflows/feature/lens-review.feature +0 -566
  74. package/src/workflows/feature/naive-acceptance.feature +0 -147
  75. package/src/workflows/feature/naive-test.feature +0 -263
  76. package/src/workflows/feature/one-step-land.feature +0 -93
  77. package/src/workflows/feature/planning.ts +0 -41
  78. package/src/workflows/feature/refactor-absorbs.feature +0 -131
  79. package/src/workflows/feature/refactor-first.feature +0 -158
  80. package/src/workflows/feature/refactor-lens-models.feature +0 -79
  81. package/src/workflows/feature/refactor-rebuild.feature +0 -273
  82. package/src/workflows/feature/refactor-review.feature +0 -1528
  83. package/src/workflows/feature/refactor.test.ts +0 -1220
  84. package/src/workflows/feature/refactor.ts +0 -368
  85. package/src/workflows/feature/release-flag.feature +0 -167
  86. package/src/workflows/feature/release-flag.test.ts +0 -49
  87. package/src/workflows/feature/release-flag.ts +0 -46
  88. package/src/workflows/feature/review-gate.feature +0 -241
  89. package/src/workflows/feature/reviewer-walkthrough.feature +0 -142
  90. package/src/workflows/feature/risk-tier.feature +0 -351
  91. package/src/workflows/feature/seam-rejection.feature +0 -146
  92. package/src/workflows/feature/seam.feature +0 -297
  93. package/src/workflows/feature/seam.test.ts +0 -527
  94. package/src/workflows/feature/seam.ts +0 -426
  95. package/src/workflows/feature/standards.feature +0 -354
  96. package/src/workflows/feature/steps.test.ts +0 -65
  97. package/src/workflows/feature/steps.ts +0 -45
  98. package/src/workflows/feature/tier-pin.feature +0 -66
  99. package/src/workflows/feature/tier.test.ts +0 -166
  100. package/src/workflows/feature/tier.ts +0 -56
  101. package/src/workflows/fix/fix-lens-origin.feature +0 -114
  102. package/src/workflows/fix/fix-quality.feature +0 -212
  103. package/src/workflows/fix/fix.feature +0 -79
  104. package/src/workflows/fix/fix.test.ts +0 -74
  105. package/src/workflows/fix/fix.ts +0 -52
  106. package/src/workflows/fix/index.ts +0 -6
  107. package/src/workflows/index.ts +0 -47
  108. package/src/workflows/review/index.ts +0 -6
  109. package/src/workflows/review/review-door.feature +0 -199
  110. package/src/workflows/review/review.test.ts +0 -27
  111. package/src/workflows/review/review.ts +0 -60
  112. package/src/workflows/rollout/index.ts +0 -6
  113. package/src/workflows/rollout/rollout.feature +0 -510
  114. package/src/workflows/rollout/rollout.test.ts +0 -263
  115. package/src/workflows/rollout/rollout.ts +0 -82
  116. package/src/workflows/shared/__fixtures__/feature-collecting-prompt.txt +0 -98
  117. package/src/workflows/shared/access.test.ts +0 -62
  118. package/src/workflows/shared/access.ts +0 -24
  119. package/src/workflows/shared/config.fixture.ts +0 -12
  120. package/src/workflows/shared/fences.ts +0 -24
  121. package/src/workflows/shared/health.test.ts +0 -148
  122. package/src/workflows/shared/health.ts +0 -191
  123. package/src/workflows/shared/learn.test.ts +0 -140
  124. package/src/workflows/shared/learn.ts +0 -201
  125. package/src/workflows/shared/lenses.test.ts +0 -39
  126. package/src/workflows/shared/lenses.ts +0 -294
  127. package/src/workflows/shared/options.test.ts +0 -157
  128. package/src/workflows/shared/options.ts +0 -92
  129. package/src/workflows/shared/progress.feature +0 -124
  130. package/src/workflows/shared/prose.ts +0 -263
  131. package/src/workflows/shared/recheck.feature +0 -60
  132. package/src/workflows/shared/registry.test.ts +0 -345
  133. package/src/workflows/shared/registry.ts +0 -183
  134. package/src/workflows/shared/reserved.ts +0 -11
  135. package/src/workflows/shared/review.test.ts +0 -1062
  136. package/src/workflows/shared/review.ts +0 -446
  137. package/src/workflows/shared/skills.test.ts +0 -121
  138. package/src/workflows/shared/skills.ts +0 -49
  139. package/src/workflows/shared/standards.test.ts +0 -90
  140. package/src/workflows/shared/standards.ts +0 -156
  141. package/src/workflows/shared/steps.test.ts +0 -219
  142. package/src/workflows/shared/steps.ts +0 -201
  143. package/src/workflows/shared/tail.test.ts +0 -454
  144. package/src/workflows/shared/tail.ts +0 -264
  145. package/src/workflows/shared/text.fixture.ts +0 -128
  146. package/src/workflows/shared/text.test.ts +0 -1430
  147. package/src/workflows/shared/text.ts +0 -1700
  148. package/src/workflows/shared/threads.test.ts +0 -129
  149. package/src/workflows/shared/vars.ts +0 -47
  150. package/src/workflows/shared/workflows.steps.ts +0 -54
@@ -1,166 +0,0 @@
1
- import { afterEach, describe, expect, it } from "vitest"
2
- import { installContext, type FlowContext } from "../../flows/index.js"
3
- import { fixtureContext } from "../shared/text.fixture.js"
4
- import { productionSignals, readRiskTier, recordRisk, riskTierOn } from "./tier.js"
5
-
6
- afterEach(() => installContext(undefined))
7
-
8
- const withVars = (vars: Record<string, string>) => installContext(fixtureContext({ vars }))
9
-
10
- describe("riskTierOn", () => {
11
- it.each([
12
- [{ flag_risk_tier: "1" }, true],
13
- [{ flag_risk_tier: "0" }, false],
14
- [{}, false],
15
- ])("%j is %s", (vars, expected) => {
16
- withVars(vars)
17
- expect(riskTierOn()).toBe(expected)
18
- })
19
- })
20
-
21
- describe("readRiskTier", () => {
22
- const doc = (body: string) =>
23
- `# Requirements\n\n## Risk Tier\n\n${body}\n\n## Answered Questions\n`
24
-
25
- it.each(["low", "`low`", "**Low** — trivial copy", "LOW - copy", "_low_ — x"])(
26
- "reads %j as low",
27
- (body) => expect(readRiskTier(doc(body))).toBe("low"),
28
- )
29
-
30
- it.each(["high", "medium", "lower", "", " \n\n"])("reads %j as high", (body) =>
31
- expect(readRiskTier(doc(body))).toBe("high"),
32
- )
33
-
34
- it("reads a missing section and undefined as high", () => {
35
- expect(readRiskTier("# Requirements\n\n## Other\n\nlow\n")).toBe("high")
36
- expect(readRiskTier(undefined)).toBe("high")
37
- })
38
-
39
- it("takes the first non-blank line only and stops at the next section", () => {
40
- expect(readRiskTier("## Risk Tier\n\nhigh — why\nlow\n")).toBe("high")
41
- expect(readRiskTier("## Risk Tier\n\n## Other\n\nlow\n")).toBe("high")
42
- })
43
- })
44
-
45
- describe("readRiskTier fences", () => {
46
- it("ignores a backtick-fenced example above the real section", () => {
47
- const text = "```\n## Risk Tier\n\nlow\n```\n\n## Risk Tier\n\nhigh\n"
48
- expect(readRiskTier(text)).toBe("high")
49
- })
50
-
51
- it("reads a fenced example with no real section as high", () => {
52
- expect(readRiskTier("```md\n## Risk Tier\n\nlow\n```\n")).toBe("high")
53
- })
54
-
55
- it("keeps the signals section open across a fence and skips fenced items", () => {
56
- const signals = "## Production Signals\n- before\n```\n# x\n- fake\n```\n- after\n"
57
- expect(productionSignals(signals)).toEqual(["before", "after"])
58
- })
59
-
60
- it("ignores a tilde-fenced example above the real section", () => {
61
- const text = "~~~\n## Risk Tier\n\nlow\n~~~\n\n## Risk Tier\n\nhigh\n"
62
- expect(readRiskTier(text)).toBe("high")
63
- })
64
-
65
- it("does not read a fence opener's info string as the tier", () => {
66
- expect(readRiskTier("## Risk Tier\n\n```low\nhigh\n```\n")).toBe("high")
67
- expect(readRiskTier("## Risk Tier\n\n~~~low\nlow\n~~~\n")).toBe("high")
68
- })
69
-
70
- it("fails closed on an unclosed fence before the real section", () => {
71
- expect(readRiskTier("```\nstray\n\n## Risk Tier\n\nlow\n")).toBe("high")
72
- })
73
-
74
- it("does not close a 4-backtick fence with 3 backticks", () => {
75
- const text = "````\n```\n## Risk Tier\n\nlow\n````\n"
76
- expect(readRiskTier(text)).toBe("high")
77
- })
78
-
79
- it("does not open a fence on a backtick line indented 4 spaces", () => {
80
- expect(readRiskTier(" ```\n## Risk Tier\n\nlow\n")).toBe("low")
81
- })
82
- })
83
-
84
- describe("readRiskTier fence closers", () => {
85
- it.each([
86
- ["a tilde line does not close a backtick fence", "```\n~~~\n## Risk Tier\n\nlow\n```\n"],
87
- ["a closer with an info string does not close", "```\n```js\n## Risk Tier\n\nlow\n```\n"],
88
- ])("%s", (_, text) => {
89
- expect(readRiskTier(text)).toBe("high")
90
- })
91
- })
92
-
93
- describe("productionSignals", () => {
94
- it("lists top-level items only, skipping blanks and indented lines", () => {
95
- const text = `## Production Signals
96
-
97
- - error rate on /pay
98
- not a signal
99
- - nested detail
100
- -
101
- - spaced out\t signal
102
- * star item
103
-
104
- ## Answered Questions
105
-
106
- - not a signal
107
- `
108
- expect(productionSignals(text)).toEqual([
109
- "error rate on /pay",
110
- "spaced out signal",
111
- "star item",
112
- ])
113
- })
114
-
115
- it("skips a fenced Production Signals example", () => {
116
- const text = "```\n## Production Signals\n- fake\n```\n\n## Production Signals\n- real\n"
117
- expect(productionSignals(text)).toEqual(["real"])
118
- })
119
-
120
- it("drops control characters", () => {
121
- expect(productionSignals("## Production Signals\n- a\u001bb\u0085c\n")).toEqual(["abc"])
122
- })
123
-
124
- it("is empty for a missing section or undefined", () => {
125
- expect(productionSignals("## Risk Tier\nlow\n")).toEqual([])
126
- expect(productionSignals(undefined)).toEqual([])
127
- })
128
- })
129
-
130
- describe("recordRisk", () => {
131
- const record = (requirements: string | undefined) => {
132
- const marks: [string, string][] = []
133
- installContext({
134
- ...fixtureContext({ read: () => requirements }),
135
- mark: (name: string, value: string) => marks.push([name, value]),
136
- } as unknown as FlowContext)
137
- return { tier: recordRisk(), marks }
138
- }
139
-
140
- it("marks the tier first, then one production-signal each", () => {
141
- const { tier, marks } = record(
142
- "## Risk Tier\nhigh — payments\n\n## Production Signals\n- a\n- b\n",
143
- )
144
- expect(tier).toBe("high")
145
- expect(marks).toEqual([
146
- ["risk-tier", "high"],
147
- ["production-signal", "a"],
148
- ["production-signal", "b"],
149
- ])
150
- })
151
-
152
- it("marks risk-tier=low too", () => {
153
- const { tier, marks } = record("## Risk Tier\nlow — copy\n\n## Production Signals\n- a\n")
154
- expect(tier).toBe("low")
155
- expect(marks).toEqual([
156
- ["risk-tier", "low"],
157
- ["production-signal", "a"],
158
- ])
159
- })
160
-
161
- it("treats a missing file as high", () => {
162
- const { tier, marks } = record(undefined)
163
- expect(tier).toBe("high")
164
- expect(marks).toEqual([["risk-tier", "high"]])
165
- })
166
- })
@@ -1,56 +0,0 @@
1
- import { mark, read, vars } from "../../flows/index.js"
2
- import { markFenced } from "../shared/fences.js"
3
- import { REQUIREMENTS } from "../shared/steps.js"
4
-
5
- export type RiskTier = "low" | "high"
6
-
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
-
10
- const sectionLines = (
11
- text: string | undefined,
12
- title: string,
13
- ): readonly { line: string; fenced: boolean }[] => {
14
- if (text === undefined) return []
15
- const heading = new RegExp(`^##[ \\t]+${title}[ \\t]*$`, "i")
16
- // An unclosed fence hides the rest, so the tier reads `high` (fail-closed).
17
- const lines = markFenced(text)
18
- const start = lines.findIndex((l) => !l.fenced && heading.test(l.line))
19
- if (start < 0) return []
20
- const rest = lines.slice(start + 1)
21
- const end = rest.findIndex((l) => !l.fenced && /^#{1,2}[ \t]/.test(l.line))
22
- return end < 0 ? rest : rest.slice(0, end)
23
- }
24
-
25
- /** Anything but a legible `low` is `high`: under-tiering is the risky direction. */
26
- export const readRiskTier = (requirements: string | undefined): RiskTier => {
27
- const first = sectionLines(requirements, "Risk Tier").find(
28
- (l) => !l.fenced && l.line.trim() !== "",
29
- )?.line
30
- const word = first?.trim().split(/\s+/)[0]?.replace(/[`*_]/g, "").toLowerCase()
31
- return word === "low" ? "low" : "high"
32
- }
33
-
34
- // eslint-disable-next-line no-control-regex -- the control range IS the point
35
- const CONTROL = /[\x00-\x1f\x7f-\x9f\u2028\u2029]/g
36
-
37
- const tidy = (text: string): string => text.replace(/\s+/g, " ").replace(CONTROL, "").trim()
38
-
39
- export const productionSignals = (requirements: string | undefined): readonly string[] => {
40
- const items: string[] = []
41
- for (const { line, fenced } of sectionLines(requirements, "Production Signals")) {
42
- if (fenced) continue
43
- const top = /^[-*+][ \t]+(.*)$/.exec(line)
44
- if (top !== null) items.push(top[1]!)
45
- }
46
- return items.map(tidy).filter((item) => item !== "")
47
- }
48
-
49
- /** The tier is always marked, first, so the last `risk-tier` mark opens the current lap's marks. */
50
- export const recordRisk = (): RiskTier => {
51
- const requirements = read(REQUIREMENTS)
52
- const tier = readRiskTier(requirements)
53
- mark("risk-tier", tier)
54
- for (const signal of productionSignals(requirements)) mark("production-signal", signal)
55
- return tier
56
- }
@@ -1,114 +0,0 @@
1
- @inmem
2
- Feature: each finding at the finding gate names the lens that wrote it
3
-
4
- Lenses append to `.gtd/QUALITY.md` in turn, so a finding belongs to the lens
5
- whose turn added it — even when two lenses give findings the same title.
6
-
7
- Background:
8
- Given the shipped workflows, as gtd install scaffolds them
9
- And an environment variable "GTD_QUALITYREVIEWS" set to "correctness,tests"
10
- And a file "src/calc.ts" with:
11
- """
12
- export const add = (a: number, b: number) => a + b
13
- """
14
- And the working tree is committed as "feat: add calculator"
15
- And a file ".gtd/REVIEW.orig.md" with:
16
- """
17
- # Review: abc1234
18
-
19
- <!-- base: 0000000 -->
20
-
21
- ## calc
22
-
23
- - [ ] ./src/calc.ts#1-1
24
- new add function
25
- """
26
- And a file ".gtd/REVIEW.md" with:
27
- """
28
- # Review: abc1234
29
-
30
- <!-- base: 0000000 -->
31
-
32
- ## calc
33
-
34
- - [ ] ./src/calc.ts#1-1
35
- new add function — rename it to sum
36
- """
37
- And the working tree is committed as "chore: hand off a review"
38
- And step "notes.fixing" writes "src/calc.ts" with:
39
- """
40
- export const sum = (a: number, b: number) => a + b
41
- """
42
- And step "notes.closing" runs its script
43
- And step "build.health.check" changes nothing
44
- And step "build.quality.correctness.reviewing" writes ".gtd/QUALITY.md" with:
45
- """
46
- # Quality
47
-
48
- ## sum is untested
49
-
50
- From correctness.
51
- """
52
- And step "build.quality.tests.reviewing" writes ".gtd/QUALITY.md" with:
53
- """
54
- # Quality
55
-
56
- ## sum is untested
57
-
58
- From correctness.
59
-
60
- ## sum is untested
61
-
62
- From tests.
63
- """
64
- And step "build.quality.gating" runs its script
65
- And step "build.quality.closing" runs its script
66
- And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
67
- """
68
- # Review: abc1234
69
-
70
- <!-- base: 0000000 -->
71
-
72
- ## calc
73
-
74
- - [ ] ./src/calc.ts#1-1
75
- renamed to sum
76
- """
77
- And step "build.review.carrying" runs its script
78
-
79
- Scenario: two lenses' findings with one title each name their own lens
80
- Given judge step "build.quality.triage" answers:
81
- """
82
- [{"id":"Q1","answer":"design","p":0.9},{"id":"Q2","answer":"design","p":0.9}]
83
- """
84
- When gtd opens door "fix"
85
- And the process is driven
86
- Then the process rests at "build.quality.gate"
87
- And ".gtd/QUALITY.md" contains:
88
- """
89
- ## sum is untested
90
-
91
- _From lens correctness._
92
-
93
- From correctness.
94
-
95
- - [ ] fix
96
-
97
- ## sum is untested
98
-
99
- _From lens tests._
100
-
101
- From tests.
102
-
103
- - [ ] fix
104
- """
105
- When gtd lands
106
- And the process is driven
107
- Then the process rests at "build.review.await-review"
108
- And ".gtd/REVIEW.md" contains:
109
- """
110
- Dropped at the finding gate:
111
-
112
- - sum is untested (lens correctness)
113
- - sum is untested (lens tests)
114
- """
@@ -1,212 +0,0 @@
1
- @inmem
2
- Feature: fix's quality lap is triaged, and its leftovers are decided at the finding gate
3
-
4
- A judge sorts the lap's findings: mechanical ones are fixed for up to three
5
- turns, and the design ones — with whatever the fix turns left, and the
6
- noise — wait at the finding gate, never at an escalation. A ticked one is
7
- fixed on the spot; the hand-off review lists what became of each in its
8
- summary and carries no finding on to the next `fix`. With no requirements
9
- to check against, the `criteria-coverage` lens runs no turn.
10
-
11
- Background:
12
- Given the shipped workflows, as gtd install scaffolds them
13
- And an environment variable "GTD_QUALITYREVIEWS" set to "criteria-coverage, correctness"
14
- And a file "src/calc.ts" with:
15
- """
16
- export const add = (a: number, b: number) => a + b
17
- """
18
- And the working tree is committed as "feat: add calculator"
19
- And a file ".gtd/REVIEW.orig.md" with:
20
- """
21
- # Review: abc1234
22
-
23
- <!-- base: 0000000 -->
24
-
25
- ## calc
26
-
27
- - [ ] ./src/calc.ts#1-1
28
- new add function
29
- """
30
- And a file ".gtd/REVIEW.md" with:
31
- """
32
- # Review: abc1234
33
-
34
- <!-- base: 0000000 -->
35
-
36
- ## calc
37
-
38
- - [ ] ./src/calc.ts#1-1
39
- new add function — rename it to sum
40
- """
41
- And the working tree is committed as "chore: hand off a review"
42
- And step "notes.fixing" writes "src/calc.ts" with:
43
- """
44
- export const sum = (a: number, b: number) => a + b
45
- """
46
- And step "notes.closing" runs its script
47
- And step "build.health.check" changes nothing
48
- And step "build.quality.correctness.reviewing" writes ".gtd/QUALITY.md" with:
49
- """
50
- # Quality
51
-
52
- ## sum has no negative test
53
-
54
- Add a test summing negative numbers.
55
-
56
- ## sum should be named plus
57
-
58
- The glossary says plus.
59
- """
60
- And step "build.quality.sorting" runs its script
61
- And step "build.quality.gating" runs its script
62
- And step "build.quality.picking" runs its script
63
- And step "build.quality.closing" runs its script
64
- And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
65
- """
66
- # Review: abc1234
67
-
68
- <!-- base: 0000000 -->
69
-
70
- ## calc
71
-
72
- - [ ] ./src/calc.ts#1-1
73
- renamed to sum
74
- """
75
- And step "build.review.carrying" runs its script
76
-
77
- Scenario: a design finding and one the fix cap left reach the finding gate, and a ticked one is fixed there
78
- Given judge step "build.quality.triage" answers:
79
- """
80
- [{"id":"Q1","answer":"mechanical","p":0.9},{"id":"Q2","answer":"design","p":0.9}]
81
- """
82
- And step "build.fix.quality.fixing" changes nothing
83
- When gtd opens door "fix"
84
- And the process is driven
85
- Then the process rests at "build.quality.gate"
86
- And no commit body contains "build.health.describe"
87
- And no commit body contains "build.quality.criteria-coverage"
88
- And ".gtd/QUALITY.md" contains:
89
- """
90
- ## sum should be named plus
91
-
92
- _From lens correctness._
93
-
94
- The glossary says plus.
95
-
96
- - [ ] fix
97
-
98
- ## sum has no negative test
99
-
100
- _From lens correctness. The fixer left it unresolved._
101
-
102
- Add a test summing negative numbers.
103
-
104
- - [ ] fix
105
- """
106
- Given a file ".gtd/QUALITY.md" with:
107
- """
108
- # Quality
109
-
110
- ## sum should be named plus
111
-
112
- The glossary says plus.
113
-
114
- - [x] fix
115
-
116
- ## sum has no negative test
117
-
118
- Add a test summing negative numbers.
119
-
120
- - [ ] fix
121
- """
122
- And step "build.fix.quality.fixing" is no longer scripted
123
- And step "build.fix.quality.fixing" writes "src/calc.ts" with:
124
- """
125
- export const plus = (a: number, b: number) => a + b
126
- """
127
- And step "build.fix.quality.fixing" deletes ".gtd/QUALITY.md"
128
- When gtd lands
129
- And the process is driven
130
- Then the process rests at "build.review.await-review"
131
- And ".gtd/QUALITY.md" does not exist
132
- And ".gtd/REVIEW.md" contains:
133
- """
134
- Fixed at the finding gate:
135
-
136
- - sum should be named plus (
137
- """
138
- And ".gtd/REVIEW.md" contains:
139
- """
140
- Dropped at the finding gate:
141
-
142
- - sum has no negative test (lens correctness)
143
- """
144
- And ".gtd/REVIEW.md" does not contain "Tick exactly one:"
145
- And the commit subjects end with:
146
- """
147
- gtd(human): build.quality.gate → build.quality.picking
148
- gtd(check): build.quality.picking → build.fix.quality.fixing
149
- gtd(agent): build.fix.quality.fixing → build.health.check
150
- gtd(check): build.health.check → build.review.reviewing
151
- gtd(agent): build.review.reviewing → build.review.carrying
152
- gtd(check): build.review.carrying → build.review.await-review
153
- """
154
-
155
- Scenario: a fixed finding and a noise one are listed in the review
156
- Given judge step "build.quality.triage" answers:
157
- """
158
- [{"id":"Q1","answer":"mechanical","p":0.9},{"id":"Q2","answer":"noise","p":0.9}]
159
- """
160
- And step "build.fix.quality.fixing" writes "src/calc.test.ts" with:
161
- """
162
- it("sums negative numbers", () => {})
163
- """
164
- And step "build.fix.quality.fixing" deletes ".gtd/QUALITY.md"
165
- And step "build.quality.gate" changes nothing
166
- When gtd opens door "fix"
167
- And the process is driven
168
- Then the process rests at "build.review.await-review"
169
- And ".gtd/REVIEW.md" contains "Fixed automatically:"
170
- And ".gtd/REVIEW.md" contains "- sum has no negative test ("
171
- And ".gtd/REVIEW.md" contains the short hash of the commit "gtd(agent): build.fix.quality.fixing → build.health.check"
172
- And ".gtd/REVIEW.md" contains "- sum should be named plus (p=0.9, lens correctness)"
173
-
174
- Scenario: a risk the hand-off reviewer marks is fixed and re-reviewed in its own draft, the summary added once
175
- Given judge step "build.quality.triage" answers:
176
- """
177
- [{"id":"Q1","answer":"mechanical","p":0.9},{"id":"Q2","answer":"noise","p":0.9}]
178
- """
179
- And step "build.fix.quality.fixing" deletes ".gtd/QUALITY.md"
180
- And step "build.quality.gate" changes nothing
181
- And step "build.review.reviewing" is no longer scripted
182
- And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
183
- """
184
- # Review: abc1234
185
-
186
- <!-- base: 0000000 -->
187
-
188
- ## calc
189
-
190
- - [ ] ./src/calc.ts#1-1 — Risk: overflows on large numbers
191
- """
192
- When gtd opens door "fix"
193
- And the process is driven
194
- Then the process rests at "build.review.fix.risks.fixing"
195
- And ".gtd/REVIEW.md" does not contain "## Quality lap"
196
- Given step "build.review.reviewing" is no longer scripted
197
- And step "build.review.reviewing" replaces the text "Risk: overflows on large numbers" in ".gtd/REVIEW.md" with "sum, now guarded"
198
- And step "build.review.fix.risks.fixing" changes nothing
199
- When the process is driven
200
- Then the process rests at "build.review.await-review"
201
- And ".gtd/REVIEW.md" contains "sum, now guarded"
202
- And ".gtd/REVIEW.md" contains "## Quality lap" exactly once
203
- And ".gtd/REVIEW.md" contains "## calc" exactly once
204
- And the commit subjects end with:
205
- """
206
- gtd(check): build.quality.closing → build.review.reviewing
207
- gtd(agent): build.review.reviewing → build.review.fix.risks.fixing
208
- gtd(agent): build.review.fix.risks.fixing → build.health.check
209
- gtd(check): build.health.check → build.review.reviewing
210
- gtd(agent): build.review.reviewing → build.review.carrying
211
- gtd(check): build.review.carrying → build.review.await-review
212
- """
@@ -1,79 +0,0 @@
1
- Feature: fix fixes the notes a hand-off leaves it
2
-
3
- A hand-off is `.gtd/REVIEW.md` with the human's notes beside the reviewer's
4
- own `.gtd/REVIEW.orig.md`; `gtd door fix` picks both up.
5
-
6
- Background:
7
- Given the shipped workflows, as gtd install scaffolds them
8
- And an environment variable "GTD_QUALITYREVIEWS" set to ""
9
- And a file "src/calc.ts" with:
10
- """
11
- export const add = (a: number, b: number) => a + b
12
- """
13
- And the working tree is committed as "feat: add calculator"
14
-
15
- Scenario: a handed-off note is fixed, and both review files are removed
16
- Given a file ".gtd/REVIEW.orig.md" with:
17
- """
18
- # Review: abc1234
19
-
20
- <!-- base: 0000000 -->
21
-
22
- ## calc
23
-
24
- - [ ] ./src/calc.ts#1-1
25
- new add function
26
- """
27
- And a file ".gtd/REVIEW.md" with:
28
- """
29
- # Review: abc1234
30
-
31
- <!-- base: 0000000 -->
32
-
33
- ## calc
34
-
35
- - [ ] ./src/calc.ts#1-1
36
- new add function — rename it to sum
37
- """
38
- And the working tree is committed as "chore: hand off a review"
39
- And step "build.health.check" changes nothing
40
- And step "build.review.reviewing" writes ".gtd/REVIEW.md" with:
41
- """
42
- # Review: abc1234
43
-
44
- <!-- base: 0000000 -->
45
-
46
- ## calc
47
-
48
- - [ ] ./src/calc.ts#1-1
49
- new add function
50
- """
51
- And step "notes.fixing" writes "src/calc.ts" with:
52
- """
53
- export const sum = (a: number, b: number) => a + b
54
- """
55
- And step "notes.closing" runs its script
56
- When gtd opens door "fix"
57
- Then the resting step's content contains "rename it to sum"
58
- # The fix goes to its own review, which the scripted reviewer writes afresh.
59
- When the process is driven
60
- Then the process rests at "build.review.await-review"
61
- And the commit subjects end with:
62
- """
63
- gtd(human): notes.fixing
64
- gtd(agent): notes.fixing → notes.closing
65
- gtd(check): notes.closing → build.health.check
66
- gtd(check): build.health.check → build.review.reviewing
67
- gtd(agent): build.review.reviewing → build.review.await-review
68
- """
69
- And ".gtd/REVIEW.orig.md" does not exist
70
- And ".gtd/REVIEW.md" contains "new add function"
71
- And "src/calc.ts" contains "sum"
72
-
73
- Scenario: a reviewer's copy with no review is refused
74
- Given a file ".gtd/REVIEW.orig.md" with:
75
- """
76
- # Review: abc1234
77
- """
78
- And the working tree is committed as "chore: stray copy"
79
- Then opening door "fix" is refused with "has no .gtd/REVIEW.md"