@pmelab/gtd 50.0.0 → 51.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 +32 -24
- package/dist/chunks/{reserved-CdOzKFVX.mjs → reserved-CUkk9XgL.mjs} +93 -4
- package/dist/chunks/{review-BChXEl2Y.mjs → review-BaCXlIT2.mjs} +2 -2
- package/dist/chunks/{tail-DRM2eC1z.mjs → tail-CX6Pdsql.mjs} +1 -1
- package/dist/workflows/cleanup.mjs +2 -2
- package/dist/workflows/feature.mjs +144 -11
- 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 +234 -12
- package/package.json +1 -1
- package/src/workflows/feature/coverage.feature +1 -0
- package/src/workflows/feature/fast-path.feature +1 -0
- package/src/workflows/feature/feature.ts +4 -1
- package/src/workflows/feature/flag-mode.feature +1 -1
- package/src/workflows/feature/lens-models.feature +1 -0
- package/src/workflows/feature/lens-review.feature +1 -0
- package/src/workflows/feature/one-step-land.feature +1 -0
- package/src/workflows/feature/prototype-rounds.feature +152 -0
- package/src/workflows/feature/prototype.feature +419 -0
- package/src/workflows/feature/prototype.test.ts +43 -0
- package/src/workflows/feature/prototype.ts +181 -0
- package/src/workflows/feature/refactor-absorbs.feature +9 -1
- package/src/workflows/feature/refactor-first.feature +13 -3
- package/src/workflows/feature/refactor-rebuild.feature +29 -5
- package/src/workflows/feature/refactor-review.feature +111 -13
- package/src/workflows/feature/refactor.test.ts +14 -4
- package/src/workflows/feature/refactor.ts +2 -0
- package/src/workflows/feature/review-answers.feature +1 -0
- package/src/workflows/feature/review-gate.feature +1 -0
- package/src/workflows/feature/reviewer-walkthrough.feature +1 -0
- package/src/workflows/feature/seam-rejection.feature +1 -0
- package/src/workflows/feature/seam.feature +1 -0
- package/src/workflows/feature/seam.test.ts +3 -2
- package/src/workflows/feature/seam.ts +19 -5
- package/src/workflows/feature/severity-budget.feature +1 -0
- package/src/workflows/feature/severity-sorted-review.feature +1 -0
- package/src/workflows/feature/slice-findings.feature +1 -0
- package/src/workflows/feature/slicing-cap.feature +9 -0
- package/src/workflows/feature/slicing.feature +1 -0
- package/src/workflows/feature/standards.feature +1 -0
- package/src/workflows/shared/options.ts +1 -0
- package/src/workflows/shared/prose.ts +6 -0
- package/src/workflows/shared/skills.test.ts +4 -0
- package/src/workflows/shared/skills.ts +5 -0
- package/src/workflows/shared/steps.ts +1 -0
- package/src/workflows/shared/text.ts +104 -3
- package/src/workflows/shared/vars.ts +3 -0
|
@@ -9,6 +9,7 @@ Feature: every slice's quality lap is triaged, and its leftovers wait for the re
|
|
|
9
9
|
|
|
10
10
|
Background:
|
|
11
11
|
Given the shipped workflows, as gtd install scaffolds them
|
|
12
|
+
And an environment variable "GTD_PROTOTYPEROUNDS" set to "0"
|
|
12
13
|
And an environment variable "GTD_QUALITYREVIEWS" set to "correctness"
|
|
13
14
|
And an environment variable "GTD_FLAGMODE" set to "false"
|
|
14
15
|
And an environment variable "GTD_SLICEMAXCRITERIA" set to "1"
|
|
@@ -12,3 +12,12 @@ Feature: a bad sliceMaxCriteria refuses the landing that would pin it
|
|
|
12
12
|
# Something
|
|
13
13
|
"""
|
|
14
14
|
Then driving the process is refused with "sliceMaxCriteria must be a positive integer, got \"0\""
|
|
15
|
+
|
|
16
|
+
Scenario: a prototypeRounds that is not a whole number refuses the idle landing
|
|
17
|
+
Given the shipped workflows, as gtd install scaffolds them
|
|
18
|
+
And an environment variable "GTD_PROTOTYPEROUNDS" set to "-1"
|
|
19
|
+
And a file "TODO.md" with:
|
|
20
|
+
"""
|
|
21
|
+
# Something
|
|
22
|
+
"""
|
|
23
|
+
Then driving the process is refused with "prototypeRounds must be a non-negative integer, got \"-1\""
|
|
@@ -8,6 +8,7 @@ Feature: a change with more criteria than the cap is built in coarse slices
|
|
|
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"
|
|
11
12
|
And an environment variable "GTD_QUALITYREVIEWS" set to ""
|
|
12
13
|
And an environment variable "GTD_FLAGMODE" set to "false"
|
|
13
14
|
And an environment variable "GTD_SLICEMAXCRITERIA" set to "2"
|
|
@@ -11,6 +11,7 @@ Feature: the review learns standards from the human's answers
|
|
|
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"
|
|
14
15
|
And an environment variable "GTD_QUALITYREVIEWS" set to "correctness"
|
|
15
16
|
And an environment variable "GTD_FLAGMODE" set to "false"
|
|
16
17
|
And a file "src/calc.ts" with:
|
|
@@ -88,6 +88,12 @@ things when redirected — a failing check, or reviewer feedback. Stay
|
|
|
88
88
|
strictly inside that task; never touch code outside it. Treat feedback as the
|
|
89
89
|
diagnosis to act on; discard it, with reason, only when simply wrong.`
|
|
90
90
|
|
|
91
|
+
export const testerPersona = `You are the hands-on tester in gtd's build pipeline: use what was just
|
|
92
|
+
built the way a person would — run the real program, open the real
|
|
93
|
+
page, call the real endpoint — and report exactly what you did and
|
|
94
|
+
what you saw. Never fix anything yourself, and never pass a criterion
|
|
95
|
+
you did not watch hold.`
|
|
96
|
+
|
|
91
97
|
export const finisherPersona = `You are the closing identity in gtd's build pipeline — the last coder
|
|
92
98
|
before it closes. Fix a late-breaking failing check after sign-off,
|
|
93
99
|
focused and minimal. Every turn lands its own commit — nothing here
|
|
@@ -29,6 +29,10 @@ describe("the bundled workflow's skills export", () => {
|
|
|
29
29
|
"implement",
|
|
30
30
|
"implement.fix.suite",
|
|
31
31
|
"implement.health",
|
|
32
|
+
"implement.prototype",
|
|
33
|
+
"implement.prototype.fix",
|
|
34
|
+
"implement.prototype.fix.suite",
|
|
35
|
+
"implement.prototype.health",
|
|
32
36
|
"build.quality.correctness",
|
|
33
37
|
"build.quality.owasp-security",
|
|
34
38
|
"build.quality.ponytail-review",
|
|
@@ -33,6 +33,11 @@ export const skills = (
|
|
|
33
33
|
seam: ["incremental-implementation"],
|
|
34
34
|
implement: ["test-driven-development", "incremental-implementation"],
|
|
35
35
|
"implement.fix.suite": ["debugging-and-error-recovery"],
|
|
36
|
+
// The hands-on tester runs the program, never the suite: no TDD.
|
|
37
|
+
"implement.prototype": [],
|
|
38
|
+
"implement.prototype.fix": ["test-driven-development", "incremental-implementation"],
|
|
39
|
+
"implement.prototype.fix.suite": ["debugging-and-error-recovery"],
|
|
40
|
+
"implement.prototype.health": ["debugging-and-error-recovery"],
|
|
36
41
|
// `health` is shared code reached from both `implement` and `build`.
|
|
37
42
|
"implement.health": ["debugging-and-error-recovery"],
|
|
38
43
|
...lensScopes(
|
|
@@ -16,6 +16,7 @@ export const REFACTOR_NOTE = ".gtd/REFACTOR-NOTE.md"
|
|
|
16
16
|
export const QUALITY = ".gtd/QUALITY.md"
|
|
17
17
|
export const SLICES = ".gtd/SLICES.md"
|
|
18
18
|
export const HANDOFF = ".gtd/HANDOFF.md"
|
|
19
|
+
export const PROTOTYPE = ".gtd/PROTOTYPE.md"
|
|
19
20
|
|
|
20
21
|
export const planner = (): string => env.plannerModel ?? ""
|
|
21
22
|
export const coder = (): string => env.coderModel ?? ""
|
|
@@ -41,6 +41,7 @@ import {
|
|
|
41
41
|
reviewerPersona,
|
|
42
42
|
builderPersona,
|
|
43
43
|
finisherPersona,
|
|
44
|
+
testerPersona,
|
|
44
45
|
escalationPersona,
|
|
45
46
|
stateFileRules,
|
|
46
47
|
questionBar,
|
|
@@ -485,8 +486,11 @@ const acceptanceCriteriaBlock = `
|
|
|
485
486
|
Whichever lap this is, \`.gtd/REQUIREMENTS.md\` carries a
|
|
486
487
|
\`## Acceptance Criteria\` section: one \`- AC-<n>: <criterion>\` line
|
|
487
488
|
per criterion, numbered from \`AC-1\`. They bind every later step —
|
|
488
|
-
the build is done when each one holds — so each must be
|
|
489
|
-
test
|
|
489
|
+
the build is done when each one holds — so each must be behaviour a
|
|
490
|
+
test can pin: one that fails when it does not hold. A green suite, a
|
|
491
|
+
passing typecheck or lint, a generator or build that runs — the health
|
|
492
|
+
check enforces those on every lap, so none is a criterion; fold what it
|
|
493
|
+
must produce into a behaviour a test can observe. A later lap keeps every ID:
|
|
490
494
|
reword a criterion in place, append a new one with the next unused
|
|
491
495
|
number, delete a dropped one — never renumber, never reuse an ID. When
|
|
492
496
|
the file holds no list (a review loop-back rewrites it), recover the
|
|
@@ -600,7 +604,7 @@ export const clearCriteriaQuestion: JudgeQuestion = {
|
|
|
600
604
|
instructions:
|
|
601
605
|
"state.criteria lists the acceptance criteria the human's sketch (state.sketch) stated, as gtd numbered them. Decide whether they can stand as the binding definition of done, with no design conversation.",
|
|
602
606
|
criteria:
|
|
603
|
-
"yes: every criterion is clear
|
|
607
|
+
"yes: every criterion is clear behaviour a test can pin — a test would fail if it did not hold — and together they say what to build. no: any one criterion is vague, subjective or untestable, only a command can check it (a suite, typecheck, lint, build or generator run that passes), or the sketch leaves an open product question. Unsure means no.",
|
|
604
608
|
}
|
|
605
609
|
|
|
606
610
|
export const clearCriteriaMessage = (): string =>
|
|
@@ -1980,3 +1984,100 @@ Two ways forward (then run \`gtd land\`):
|
|
|
1980
1984
|
- **Overrule** — land a clean tree to finish without them. The slice records
|
|
1981
1985
|
the IDs it covers and, as \`uncovered\`, the ones it does not
|
|
1982
1986
|
`
|
|
1987
|
+
|
|
1988
|
+
export const testerSystem = (): string =>
|
|
1989
|
+
`${testerPersona}
|
|
1990
|
+
|
|
1991
|
+
${agentConduct}`
|
|
1992
|
+
|
|
1993
|
+
const PROTOTYPE_FORMAT = `- Write \`.gtd/PROTOTYPE.md\`, replacing any earlier report: one \`## \` chunk
|
|
1994
|
+
per criterion, headed \`## AC-<n>: pass\`, \`## AC-<n>: fail\` or
|
|
1995
|
+
\`## AC-<n>: blocked\`, then one chunk per problem you found outside any
|
|
1996
|
+
criterion, headed \`## Problem <short title>: fail\` (\`: pass\` once a
|
|
1997
|
+
re-test shows it fixed). Under each: the exact steps you ran, what you
|
|
1998
|
+
observed (output, a screenshot path, the error), and for a failure what
|
|
1999
|
+
you expected instead
|
|
2000
|
+
- \`blocked\` is for a criterion you could not exercise, or one whose
|
|
2001
|
+
expected behaviour itself looks wrong — say which and why: a person
|
|
2002
|
+
decides it, never a fixer`
|
|
2003
|
+
|
|
2004
|
+
export const prototypeTestingPrompt = (
|
|
2005
|
+
slice: readonly string[] | undefined,
|
|
2006
|
+
retest: boolean,
|
|
2007
|
+
): string =>
|
|
2008
|
+
`${stateFileRules}
|
|
2009
|
+
- Read \`.gtd/REQUIREMENTS.md\`: the settled requirements for this change
|
|
2010
|
+
${sliceLine(slice)}- The change is built and its suite is green. Now test it by hand: use
|
|
2011
|
+
every acceptance criterion the way a person would and watch what
|
|
2012
|
+
happens. Running the test suite is not this — it already ran
|
|
2013
|
+
- Find how this project is exercised for real, in this order: a project
|
|
2014
|
+
skill that launches or drives it (e.g. \`.claude/skills/*\`); a manual
|
|
2015
|
+
testing or running section in \`AGENTS.md\`, \`CLAUDE.md\` or \`README.md\`;
|
|
2016
|
+
failing those, the project's shape — a browser or Playwright for a web
|
|
2017
|
+
project, the built CLI in a scratch directory for a CLI, a request client
|
|
2018
|
+
for an API
|
|
2019
|
+
- Found none and recognised no shape: write only a chunk headed
|
|
2020
|
+
\`## No testing instructions\` saying what you looked for, and finish —
|
|
2021
|
+
a person is asked; never guess
|
|
2022
|
+
- Test in a disposable place only — a scratch directory outside this
|
|
2023
|
+
repository, a throwaway repository, a dev server on a free port — never
|
|
2024
|
+
against the user's real data or this working tree. Point every tool's
|
|
2025
|
+
output (screenshots, traces, test results) outside the repository too
|
|
2026
|
+
${
|
|
2027
|
+
retest
|
|
2028
|
+
? `- This is a re-test: \`.gtd/PROTOTYPE.md\` holds the last round's report and
|
|
2029
|
+
a fix turn or a person has changed the code since. Re-test every failed or blocked criterion and
|
|
2030
|
+
every problem it lists in full, then re-run the passed ones quickly
|
|
2031
|
+
`
|
|
2032
|
+
: ""
|
|
2033
|
+
}${PROTOTYPE_FORMAT}
|
|
2034
|
+
- Change nothing but \`.gtd/PROTOTYPE.md\` — a turn that does is refused
|
|
2035
|
+
- Leave everything uncommitted and finish your turn — do not commit
|
|
2036
|
+
`
|
|
2037
|
+
|
|
2038
|
+
export const prototypeFixingPrompt = (slice: readonly string[] | undefined): string =>
|
|
2039
|
+
`${stateFileRules}
|
|
2040
|
+
- Read \`.gtd/REQUIREMENTS.md\`: the settled requirements for this change
|
|
2041
|
+
${sliceLine(slice)}${criteriaBinding(true)}
|
|
2042
|
+
- Read \`.gtd/PROTOTYPE.md\`: a hands-on test of the change. Fix every
|
|
2043
|
+
\`fail\` chunk of this change's criteria${slice === undefined ? "" : " (this slice's only)"} or a problem found
|
|
2044
|
+
beside them, at its cause, with a test that shows it; leave \`blocked\`
|
|
2045
|
+
ones to the person
|
|
2046
|
+
- A \`fail\` the code does not explain (the tester misread what it saw) has
|
|
2047
|
+
nothing to fix: leave it and change nothing for it — the next round re-tests
|
|
2048
|
+
- Leave \`.gtd/PROTOTYPE.md\` as it is: the next round re-tests from it
|
|
2049
|
+
- Run \`${env.testCommand}\` and finish only once it is green
|
|
2050
|
+
- Leave everything uncommitted and finish your turn — do not commit
|
|
2051
|
+
`
|
|
2052
|
+
|
|
2053
|
+
const openItems = (items: readonly { subject: string; verdict: string }[]): string =>
|
|
2054
|
+
items.map((item) => `- ${item.subject}: ${item.verdict}`).join("\n")
|
|
2055
|
+
|
|
2056
|
+
export const prototypeOpenMessage = (
|
|
2057
|
+
items: readonly { subject: string; verdict: string }[],
|
|
2058
|
+
rounds: number,
|
|
2059
|
+
): string =>
|
|
2060
|
+
`The hands-on test of this slice still has open items${rounds > 0 ? ` after ${rounds} fix round${rounds === 1 ? "" : "s"}` : ", and none a fixer can take"}:
|
|
2061
|
+
${openItems(items)}
|
|
2062
|
+
|
|
2063
|
+
\`.gtd/PROTOTYPE.md\` holds the last report: the steps run and what was seen.
|
|
2064
|
+
|
|
2065
|
+
Two ways forward (then run \`gtd land\`):
|
|
2066
|
+
- **Fix** — change the code, or the testing instructions, yourself (the
|
|
2067
|
+
criteria are settled: an edit to them is refused); the suite runs and the
|
|
2068
|
+
slice is tested again, with a fresh round budget
|
|
2069
|
+
- **Overrule** — land a clean tree to go on to the quality lap with these
|
|
2070
|
+
items open
|
|
2071
|
+
`
|
|
2072
|
+
|
|
2073
|
+
export const prototypeUnguidedMessage = (): string =>
|
|
2074
|
+
`The hands-on test found no way to exercise this project for real — no
|
|
2075
|
+
project skill, no manual testing section in \`AGENTS.md\`, \`CLAUDE.md\` or
|
|
2076
|
+
\`README.md\`, and no project shape it recognised. \`.gtd/PROTOTYPE.md\` says
|
|
2077
|
+
what it looked for.
|
|
2078
|
+
|
|
2079
|
+
Two ways forward (then run \`gtd land\`):
|
|
2080
|
+
- **Instruct** — add testing instructions (a project skill, or a manual
|
|
2081
|
+
testing section); the slice is tested again
|
|
2082
|
+
- **Skip** — land a clean tree to go on to the quality lap untested
|
|
2083
|
+
`
|
|
@@ -41,6 +41,9 @@ export const defaults: Readonly<Record<string, string>> = {
|
|
|
41
41
|
// stopped at its context limit before a person is asked, and how many in a
|
|
42
42
|
// row may close nothing still open.
|
|
43
43
|
continuations: "3",
|
|
44
|
+
// Fix-and-retest rounds of a slice's prototype test before a person is
|
|
45
|
+
// asked; "0" skips the test.
|
|
46
|
+
prototypeRounds: "3",
|
|
44
47
|
continuationStall: "2",
|
|
45
48
|
}
|
|
46
49
|
|