@pmelab/gtd 58.2.0 → 59.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.
Files changed (133) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +115 -390
  3. package/dist/chunks/{Schema-B3o6eRNU.mjs → testkit-CMBAAyRK.mjs} +13409 -3351
  4. package/dist/gtd.bundle.mjs +76 -59
  5. package/dist/testkit/gherkin.mjs +1 -1
  6. package/dist/testkit.mjs +1 -1
  7. package/package.json +3 -42
  8. package/skills/authoring/SKILL.md +31 -25
  9. package/src/cli/Cli.test.ts +15 -19
  10. package/src/cli/Cli.ts +2 -4
  11. package/src/cli/Program.test.ts +60 -29
  12. package/src/cli/Program.ts +5 -7
  13. package/src/edge/Edge.ts +3 -3
  14. package/src/flags/index.test.ts +0 -13
  15. package/src/flags/index.ts +1 -3
  16. package/src/install/Install.test.ts +14 -11
  17. package/src/install/Install.ts +38 -15
  18. package/src/install/index.ts +1 -2
  19. package/src/replay/Replay.test.ts +1 -1
  20. package/src/replay/index.ts +1 -1
  21. package/src/step/planStart.ts +6 -1
  22. package/src/twins/FlowScripts.ts +1 -1
  23. package/src/workflow/index.ts +1 -0
  24. package/src/workflow/load.test.ts +138 -113
  25. package/src/workflow/load.ts +1 -1
  26. package/src/workflow/vars.test.ts +30 -3
  27. package/src/workflow/vars.ts +34 -2
  28. package/src/workflow-kit/index.ts +1 -1
  29. package/dist/chunks/reserved-lMYCaapY.mjs +0 -1990
  30. package/dist/chunks/review-Bfaror38.mjs +0 -427
  31. package/dist/chunks/tail-Bd7L940p.mjs +0 -355
  32. package/dist/chunks/testkit-JDtpNKyi.mjs +0 -10410
  33. package/dist/workflows/cleanup.mjs +0 -36
  34. package/dist/workflows/feature.mjs +0 -1018
  35. package/dist/workflows/fix.mjs +0 -41
  36. package/dist/workflows/review.mjs +0 -45
  37. package/dist/workflows/rollout.mjs +0 -48
  38. package/dist/workflows.mjs +0 -40651
  39. package/src/install/ConfigScaffold.ts +0 -22
  40. package/src/workflows/cleanup/cleanup-path.feature +0 -94
  41. package/src/workflows/cleanup/cleanup.feature +0 -315
  42. package/src/workflows/cleanup/cleanup.test.ts +0 -276
  43. package/src/workflows/cleanup/cleanup.ts +0 -52
  44. package/src/workflows/cleanup/index.ts +0 -6
  45. package/src/workflows/feature/acceptance-criteria-tier.feature +0 -25
  46. package/src/workflows/feature/acceptance-criteria.feature +0 -389
  47. package/src/workflows/feature/criteria-coverage.feature +0 -102
  48. package/src/workflows/feature/criteria.test.ts +0 -147
  49. package/src/workflows/feature/criteria.ts +0 -267
  50. package/src/workflows/feature/fast-path.feature +0 -93
  51. package/src/workflows/feature/feature.test.ts +0 -338
  52. package/src/workflows/feature/feature.ts +0 -156
  53. package/src/workflows/feature/green.ts +0 -19
  54. package/src/workflows/feature/index.ts +0 -18
  55. package/src/workflows/feature/lens-models.feature +0 -69
  56. package/src/workflows/feature/lens-review.feature +0 -566
  57. package/src/workflows/feature/naive-acceptance.feature +0 -147
  58. package/src/workflows/feature/naive-test.feature +0 -263
  59. package/src/workflows/feature/one-step-land.feature +0 -93
  60. package/src/workflows/feature/planning.ts +0 -41
  61. package/src/workflows/feature/refactor-absorbs.feature +0 -131
  62. package/src/workflows/feature/refactor-first.feature +0 -158
  63. package/src/workflows/feature/refactor-lens-models.feature +0 -79
  64. package/src/workflows/feature/refactor-rebuild.feature +0 -273
  65. package/src/workflows/feature/refactor-review.feature +0 -1528
  66. package/src/workflows/feature/refactor.test.ts +0 -1220
  67. package/src/workflows/feature/refactor.ts +0 -368
  68. package/src/workflows/feature/release-flag.feature +0 -167
  69. package/src/workflows/feature/release-flag.test.ts +0 -49
  70. package/src/workflows/feature/release-flag.ts +0 -46
  71. package/src/workflows/feature/review-gate.feature +0 -241
  72. package/src/workflows/feature/reviewer-walkthrough.feature +0 -142
  73. package/src/workflows/feature/risk-tier.feature +0 -351
  74. package/src/workflows/feature/seam-rejection.feature +0 -146
  75. package/src/workflows/feature/seam.feature +0 -297
  76. package/src/workflows/feature/seam.test.ts +0 -527
  77. package/src/workflows/feature/seam.ts +0 -426
  78. package/src/workflows/feature/standards.feature +0 -354
  79. package/src/workflows/feature/steps.test.ts +0 -65
  80. package/src/workflows/feature/steps.ts +0 -45
  81. package/src/workflows/feature/tier-pin.feature +0 -66
  82. package/src/workflows/feature/tier.test.ts +0 -166
  83. package/src/workflows/feature/tier.ts +0 -56
  84. package/src/workflows/fix/fix-lens-origin.feature +0 -114
  85. package/src/workflows/fix/fix-quality.feature +0 -212
  86. package/src/workflows/fix/fix.feature +0 -79
  87. package/src/workflows/fix/fix.test.ts +0 -74
  88. package/src/workflows/fix/fix.ts +0 -52
  89. package/src/workflows/fix/index.ts +0 -6
  90. package/src/workflows/index.ts +0 -47
  91. package/src/workflows/review/index.ts +0 -6
  92. package/src/workflows/review/review-door.feature +0 -199
  93. package/src/workflows/review/review.test.ts +0 -27
  94. package/src/workflows/review/review.ts +0 -60
  95. package/src/workflows/rollout/index.ts +0 -6
  96. package/src/workflows/rollout/rollout.feature +0 -510
  97. package/src/workflows/rollout/rollout.test.ts +0 -263
  98. package/src/workflows/rollout/rollout.ts +0 -82
  99. package/src/workflows/shared/__fixtures__/feature-collecting-prompt.txt +0 -98
  100. package/src/workflows/shared/access.test.ts +0 -62
  101. package/src/workflows/shared/access.ts +0 -24
  102. package/src/workflows/shared/config.fixture.ts +0 -12
  103. package/src/workflows/shared/fences.ts +0 -24
  104. package/src/workflows/shared/health.test.ts +0 -148
  105. package/src/workflows/shared/health.ts +0 -191
  106. package/src/workflows/shared/learn.test.ts +0 -140
  107. package/src/workflows/shared/learn.ts +0 -201
  108. package/src/workflows/shared/lenses.test.ts +0 -39
  109. package/src/workflows/shared/lenses.ts +0 -294
  110. package/src/workflows/shared/options.test.ts +0 -157
  111. package/src/workflows/shared/options.ts +0 -92
  112. package/src/workflows/shared/progress.feature +0 -124
  113. package/src/workflows/shared/prose.ts +0 -263
  114. package/src/workflows/shared/recheck.feature +0 -60
  115. package/src/workflows/shared/registry.test.ts +0 -345
  116. package/src/workflows/shared/registry.ts +0 -183
  117. package/src/workflows/shared/reserved.ts +0 -11
  118. package/src/workflows/shared/review.test.ts +0 -1062
  119. package/src/workflows/shared/review.ts +0 -446
  120. package/src/workflows/shared/skills.test.ts +0 -121
  121. package/src/workflows/shared/skills.ts +0 -49
  122. package/src/workflows/shared/standards.test.ts +0 -90
  123. package/src/workflows/shared/standards.ts +0 -156
  124. package/src/workflows/shared/steps.test.ts +0 -219
  125. package/src/workflows/shared/steps.ts +0 -201
  126. package/src/workflows/shared/tail.test.ts +0 -454
  127. package/src/workflows/shared/tail.ts +0 -264
  128. package/src/workflows/shared/text.fixture.ts +0 -128
  129. package/src/workflows/shared/text.test.ts +0 -1430
  130. package/src/workflows/shared/text.ts +0 -1700
  131. package/src/workflows/shared/threads.test.ts +0 -129
  132. package/src/workflows/shared/vars.ts +0 -47
  133. 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"