@pmelab/gtd 29.3.0 → 30.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 (51) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +65 -71
  3. package/claude/hooks/ship.ts +36 -25
  4. package/dist/chunks/{reserved-Dmpg6dAp.mjs → reserved-iG86IR3I.mjs} +19 -233
  5. package/dist/chunks/{tail-CLyE5VFR.mjs → tail-DA2UuJNP.mjs} +1 -1
  6. package/dist/gtd.bundle.mjs +0 -5
  7. package/dist/testkit.mjs +0 -5
  8. package/dist/workflows/cleanup.mjs +2 -2
  9. package/dist/workflows/feature.mjs +14 -180
  10. package/dist/workflows/fix.mjs +2 -2
  11. package/dist/workflows/review.mjs +2 -2
  12. package/dist/workflows/rollout.mjs +1 -1
  13. package/dist/workflows.mjs +29 -409
  14. package/package.json +1 -1
  15. package/skills/authoring/SKILL.md +15 -27
  16. package/src/cli/Cli.test.ts +6 -6
  17. package/src/edge/Edge.test.ts +7 -7
  18. package/src/flags/index.test.ts +0 -4
  19. package/src/flags/index.ts +0 -1
  20. package/src/workflow/load.test.ts +1 -1
  21. package/src/workflows/feature/fast-path.feature +1 -2
  22. package/src/workflows/feature/feature.test.ts +74 -63
  23. package/src/workflows/feature/feature.ts +13 -35
  24. package/src/workflows/feature/index.ts +0 -1
  25. package/src/workflows/feature/one-step-land.feature +4 -6
  26. package/src/workflows/feature/planning.ts +2 -27
  27. package/src/workflows/feature/refactor-absorbs.feature +1 -2
  28. package/src/workflows/feature/refactor-first.feature +1 -3
  29. package/src/workflows/feature/refactor-review.feature +0 -1
  30. package/src/workflows/feature/risk-tier.feature +2 -3
  31. package/src/workflows/feature/seam-rejection.feature +1 -3
  32. package/src/workflows/feature/seam.feature +4 -6
  33. package/src/workflows/feature/steps.test.ts +0 -20
  34. package/src/workflows/feature/steps.ts +1 -49
  35. package/src/workflows/feature/{seam-pin.feature → tier-pin.feature} +17 -11
  36. package/src/workflows/feature/tier.test.ts +3 -5
  37. package/src/workflows/feature/tier.ts +2 -2
  38. package/src/workflows/index.ts +0 -1
  39. package/src/workflows/shared/access.test.ts +0 -2
  40. package/src/workflows/shared/access.ts +0 -2
  41. package/src/workflows/shared/options.test.ts +2 -3
  42. package/src/workflows/shared/prose.ts +4 -11
  43. package/src/workflows/shared/reserved.ts +2 -2
  44. package/src/workflows/shared/skills.test.ts +0 -11
  45. package/src/workflows/shared/skills.ts +2 -9
  46. package/src/workflows/shared/steps.ts +0 -1
  47. package/src/workflows/shared/text.test.ts +4 -104
  48. package/src/workflows/shared/text.ts +15 -223
  49. package/src/workflows/shared/vars.ts +1 -3
  50. package/src/workflows/feature/packages.test.ts +0 -368
  51. package/src/workflows/feature/packages.ts +0 -173
@@ -21,7 +21,6 @@ import {
21
21
  styleFormatContract,
22
22
  agentConduct,
23
23
  designPersona,
24
- architectPersona,
25
24
  reviewerPersona,
26
25
  builderPersona,
27
26
  finisherPersona,
@@ -67,12 +66,12 @@ place to start sketching. gtd treats it as a SKETCH, not finished
67
66
  work: the very next beat unwinds it out of your working tree (its
68
67
  intent survives in history, for the triage phase to read), then
69
68
  checks the test baseline is green, then triages the reverted diff
70
- into ordered, classified concerns: product questions, then
71
- technical questions, then one package per concern, built and
72
- reviewed in parallel.
69
+ into ordered, classified concerns and resolves the product
70
+ questions, before a quick first implementation, a judged refactor
71
+ where it needs one, and the build and review.
73
72
 
74
73
  What each change does next (then run \`gtd land\`):
75
- - **Start** — make any change — gtd unwinds it out of your working tree (its intent survives in history) before checking the test baseline is green, then triages the reverted diff into ordered, classified concerns and resolves product questions, then technical ones, before building each concern's package (**unwind** -> **start-gate.check**).
74
+ - **Start** — make any change — gtd unwinds it out of your working tree (its intent survives in history) before checking the test baseline is green, then triages the reverted diff into ordered, classified concerns and resolves product questions before building the change (**unwind** -> **start-gate.check**).
76
75
  `
77
76
 
78
77
  export const unwindFailedMessage = (): string =>
@@ -175,9 +174,10 @@ Classify each as PRODUCT (user-facing/requirements) or TECHNICAL
175
174
 
176
175
  ${questionBar}
177
176
 
178
- Raise questions only for product concerns here — technical ones
179
- wait for the next phase. When every concern is TECHNICAL, write
180
- no \`## Open Questions\` section. STRICT: answer it yourself only
177
+ Raise questions for product concerns. Raise a technical concern
178
+ only when it is a genuine fork the human must settle — no later
179
+ phase asks; otherwise the builder decides it. When no concern
180
+ clears that bar, write no \`## Open Questions\` section. STRICT: answer it yourself only
181
181
  when the product default is unmistakable; a wrong intent costs a
182
182
  whole rebuild lap.
183
183
 
@@ -213,8 +213,7 @@ ${questionBarReturn}
213
213
  yourself — a loop-back runs no green-baseline gate, so the
214
214
  tree may already be red (reverting the edit can undo a fix it
215
215
  made). If red, make that breakage the first concern, ahead of
216
- everything else — every later concern's green-on-its-own
217
- property assumes the suite started green
216
+ everything else — the build assumes the suite started green
218
217
  ${riskTier ? riskTierBlock : ""}`
219
218
 
220
219
  export const designSystem = (): string =>
@@ -252,217 +251,11 @@ What each change does next (then run \`gtd land\`):
252
251
  - **Discuss** — start or continue a thread (\`- H:\`); the agent replies and this gate stops again.
253
252
  ${riskTier ? RISK_TIER_GATE_LINE : ""}`
254
253
 
255
- export const architectureAuthorPrompt = (): string =>
256
- `${styleBlock}
257
-
258
- ${styleFormatContract}
259
-
260
- ${stateFileRules}
261
- ${footnoteFoldIn}${codeThreadReplies()}
262
- - The only state files this turn touches are
263
- \`.gtd/ARCHITECTURE.md\` (write it) and \`.gtd/REQUIREMENTS.md\`
264
- (delete once folded in) — no other files for notes or output
265
- - You do not resume the design conversation — a separate
266
- machine, its own memory, a cold read every time. Read
267
- \`.gtd/REQUIREMENTS.md\` (the settled, ordered, classified
268
- concerns) in full; treat every decision there, PRODUCT or
269
- TECHNICAL alike, as settled — never re-open it
270
- - Cold means no memory of triage's own back-and-forth, not no
271
- git access. This process started at commit
272
- \`${start()}\`. Find the first turn yourself: run
273
- \`git rev-list --ancestry-path ${start()}..HEAD | tail -1\`
274
- then \`git show\` it to see what started this process — a
275
- hand-edit, a scratch note, or both
276
- - Once \`.gtd/ARCHITECTURE.md\` is written, delete
277
- \`.gtd/REQUIREMENTS.md\` — folded in, it must not linger. Leave
278
- everything uncommitted and finish
279
-
280
- ## First lap
281
-
282
- - Develop \`.gtd/ARCHITECTURE.md\` from those concerns: for each,
283
- in order, work out the *how*, building on the settled *what*
284
- - You now know the *how*, so you know each concern's file footprint
285
- — list each concern's primary paths. Merge concerns whose
286
- footprints center on the same files into one, unless the later
287
- one only consumes an interface the earlier one creates (keeps a
288
- build-on-top sequence from collapsing into one blob). This
289
- authority is to merge only, never to split — the whole problem
290
- is over-granularity
291
- - Record every merge under \`## Merged Concerns\`,
292
- carrying both merged requirements verbatim so each requirement
293
- stays traceable to its tests
294
- - A merge raises no open question and stops for no
295
- human — do not route it to \`architecture.gate\` for a veto; the
296
- human sees it when reviewing the plan
297
- - Prefer fewer, larger packages — the smallest independently
298
- valuable change, not the smallest change that compiles
299
- - Every open point here is TECHNICAL — triage already resolved
300
- the product ones, one phase earlier. PERMISSIVE: answer it
301
- yourself unless you genuinely cannot defend a default; a wrong
302
- technical call is still caught by each package's suite run and the
303
- quality lap
304
- - The narrow exception: a simplification that drops something
305
- \`.gtd/REQUIREMENTS.md\` mentions is an open question, not a
306
- silent default
307
-
308
- - \`.gtd/ARCHITECTURE.md\` is the acceptance spec the human signs
309
- off. It carries these sections, in this order:
310
- 1. \`## Open Questions\` (qa format, first, only when present)
311
- 2. \`## Interfaces\` — new and changed signatures/contracts
312
- only, as fenced TypeScript (or the repository's language)
313
- 3. \`## Call Stacks\` — seam level, entry point → module
314
- boundary; one line per hop, never per line of code
315
- 4. \`## E2E Scenarios\` — one line per user-visible behaviour,
316
- \`- e2e: <path> — <behaviour> (covers <concern>)\`, in plain
317
- words: the builder writes the scenario in the repository's
318
- own e2e framework, so never spell out Gherkin here. With no
319
- user-visible behaviour change, the literal line
320
- \`No e2e change.\` plus a one-line reason — never empty or
321
- missing
322
- 5. \`## Unit Tests\` — one \`### <interface>\` per entry of
323
- \`## Interfaces\`, each test a line
324
- \`- unit: <path> — <behaviour> (covers <concern>)\`;
325
- never against an internal helper. A requirement no test can
326
- cover (docs, README, deletions, config) goes under a
327
- \`### Chores\` heading in this section as
328
- \`- chore: <path> — <what> (covers <concern>)\`
329
- 6. \`## Merged Concerns\` — kept, when any merge happened
330
- 7. \`## Answered Questions\` — last
331
- - Coverage rule: every concern in \`.gtd/REQUIREMENTS.md\` appears
332
- in at least one \`(covers …)\` tail, as a test or a chore. Each
333
- test entry carries its file path and level (unit / e2e)
334
-
335
- ${questionBar}
336
- ## Return lap
337
-
338
- ${questionBarReturn}`
339
-
340
- export const architectSystem = (): string =>
341
- `${architectPersona}
342
-
343
- ${agentConduct}`
344
-
345
- export const architectureDecomposePrompt = (): string =>
346
- `${styleBlock}
347
-
348
- ${stateFileRules}
349
- - The only state files this turn touches are the package files
350
- under \`.gtd/packages/\` — no other files for notes or output.
351
- Never delete \`.gtd/ARCHITECTURE.md\`: package files may
352
- reference it, and it is removed with the last package
353
- - Work from \`.gtd/ARCHITECTURE.md\` if you wrote it earlier this
354
- conversation, otherwise read it (the converged technical
355
- plan). It already lists the concerns, interfaces, e2e scenarios
356
- and unit tests — this turn groups them into packages. A
357
- \`## Merged Concerns\` heading there records merges, never a
358
- concern of its own: write no package file for it
359
- - A package is one concern's slice, and each must leave the full
360
- suite green — every package boundary costs a full run, so write
361
- as few as the concerns allow. Keep the merge rule: concerns whose
362
- footprints centre on the same files stay in one package unless
363
- the later one only consumes an interface the earlier one creates.
364
- Order them interface-introducing packages first
365
- - Write the packages under \`.gtd/packages/\`, each carrying its
366
- requirement(s) — both, independently, if merged — its tasks, and
367
- each task's acceptance criteria as \`- [ ]\` checkboxes and
368
- relevant paths:
369
- - \`01-…\` onward — one vertical slice each: the unit tests,
370
- the code, the wiring (CLI entry, workflow composition, config)
371
- and every \`## E2E Scenarios\` entry its concern covers, so the
372
- slice ends with its scenarios passing. A requirement no test
373
- covers (docs, README, deletions, config) is a task of the slice
374
- it belongs to; only one no slice owns becomes a chore package,
375
- which declares no tests
376
- - Every package with tests has a \`## Tests\` section, one line per
377
- declared test, copied from the architecture entries:
378
- \`- unit: \\\`<path>\\\`\` or \`- e2e: \\\`<path>\\\`\`. Chore packages have
379
- none. List every test the package writes or changes; also list an
380
- existing test a criterion relies on, marked \`(unchanged)\` —
381
- \`- unit: \\\`<path>\\\` (unchanged)\` or
382
- \`- e2e: \\\`<path>\\\` (unchanged)\`; list no other untouched test;
383
- never mark a file the package also writes or changes — list it once,
384
- unmarked; only decompose places the marker
385
- - Leave everything uncommitted and finish
386
- `
387
-
388
- export const architectureGateAnswerMessage = (): string =>
389
- `This gate stops on every process, even with no open question, so
390
- you can discuss \`.gtd/ARCHITECTURE.md\`; changing nothing and re-running
391
- accepts it as written — unless a thread is open (see below).
392
-
393
- \`.gtd/ARCHITECTURE.md\` holds the technical plan under
394
- development. Each open question under \`## Open Questions\` offers
395
- a few options plus a \`- [ ] _your answer_\` slot. Tick exactly one
396
- box (\`- [x]\`) per question; for your own answer, replace
397
- \`_your answer_\` with your text and tick that line. A round that
398
- only leaves notes or thread replies needs no tick. Stepping is
399
- refused while a question is unanswered, unless the round adds a
400
- thread for the agent to answer.
401
-
402
- Moving on is refused while any thread is open — its last entry is
403
- the agent's. Reply with a conclusion, or delete the thread. A reply
404
- round returns to this same gate so you can read the agent's answer.
405
-
406
- You can also leave a footnote alongside an answer:
407
-
408
- ${footnoteRules}
409
- What each change does next (then run \`gtd land\`):
410
- - **Accept as-is** — change nothing and re-run; the plan stands as written. Refused while a thread is open.
411
- - **Revise answers** — tick exactly one option per open question (replace \`_your answer_\` for your own) to send it back for the agent to fold your answers in, or delete a question to skip it.
412
- - **Discuss** — start or continue a thread (\`- H:\`); the agent replies and this gate stops again.
413
- `
414
-
415
- export const packagesItemBuildingPrompt = (pkg: string): string =>
416
- `${stateFileRules}
417
- - The only state file this turn may write is \`.gtd/SATISFIED.md\`;
418
- never delete the package file (the declared-tests guard reads it
419
- after you)
420
- - The package to implement is \`${pkg}\`
421
- - First check the acceptance criteria against the current tree —
422
- an earlier fix turn may already meet them
423
- - **Every criterion already met in the tree**: write
424
- \`.gtd/SATISFIED.md\` with evidence per criterion — commit, file,
425
- symbol, issue URL, or command output — and change nothing else
426
- - **No \`## Tests\` and work outside the tree**: first check it was
427
- not already done by an earlier attempt (e.g. an existing issue
428
- with the same title via \`gh\`) and reuse that as evidence, or do
429
- the work; then write \`.gtd/SATISFIED.md\` with that evidence and
430
- change nothing else in the tree
431
- - **Any other package**: implement normally, write no
432
- \`.gtd/SATISFIED.md\`
433
- - Write the tests the package declares under \`## Tests\` first,
434
- then the code that makes them pass; the turn is refused unless
435
- every declared test is in your diff — except a line marked
436
- \`(unchanged)\`, which must exist before the turn and stay
437
- untouched — creating, editing or deleting it refuses the turn. If
438
- it does not exist yet, or the marker is wrong because the package
439
- must change that test, stop without creating it and leave it to
440
- a person
441
- - A declared e2e test is a scenario in the repository's own e2e
442
- framework for the behaviour its \`## E2E Scenarios\` entry names.
443
- Word it to fit the existing steps — reuse and generalise them
444
- rather than adding one-off ones
445
- - Implement every task the package describes, no more, no less,
446
- fanning independent ones out to parallel subagents where your
447
- harness supports it; leave other package files untouched
448
- - Leave the package file in place, everything uncommitted, then
449
- finish your turn
450
- `
451
-
452
254
  export const builderSystem = (): string =>
453
255
  `${builderPersona}
454
256
 
455
257
  ${agentConduct}`
456
258
 
457
- export const packagesItemFixSuitePrompt = (): string =>
458
- `${stateFileRules}
459
- ${fixFeedbackPrompt}
460
- - If the only way to green the suite is another package's work,
461
- make the smallest change that gets there — that package can
462
- then legitimately report itself already satisfied later
463
- - Leave everything uncommitted and finish your turn — do not commit
464
- `
465
-
466
259
  export const refactorRules = (strays: readonly string[], pattern: string): string =>
467
260
  `- Behaviour-neutral: the suite's outcome must not change
468
261
  - Change only these paths, nothing else:
@@ -518,7 +311,7 @@ export const refactorFixPrompt = (strays: readonly string[], pattern: string): s
518
311
  `${stateFileRules}
519
312
  ${fixFeedbackPrompt}
520
313
  ${refactorRules(strays, pattern)}
521
- - Never do another package's work, even when it would green the suite
314
+ - Never do work outside the refactor, even when it would green the suite
522
315
  - Leave everything uncommitted and finish your turn — do not commit
523
316
  `
524
317
 
@@ -612,7 +405,7 @@ export const conventionsBrief = `- Read every \`AGENTS.md\` and \`CLAUDE.md\` in
612
405
  export const specChallengeBrief = `- Find this process's planning documents in history:
613
406
  \`git log <start>..HEAD\` (\`<start>\` is the process start named in parentheses above, NOT the review base) over the steering directory
614
407
  (\`.gtd/\`), then \`git show\` the last version of the
615
- requirements, architecture and package files
408
+ requirements file
616
409
  - Flag a spec decision that conflicts with a system invariant — an
617
410
  existing test, a documented constraint, or a data invariant
618
411
  other code relies on — naming the decision and the invariant
@@ -686,8 +479,8 @@ When you've been through the whole diff, run \`gtd land\`:
686
479
  - **Leave notes** — a note on a \`.gtd/REVIEW.md\` line, a footnote
687
480
  anchored to a hunk, or prose under a chunk. Each note is judged on its
688
481
  own (**review.triage** gives one verdict per note):
689
- - \`edit\` — a change request: goes to **review.collecting** and a
690
- FULL development lap, re-planned from scratch
482
+ - \`edit\` — a change request: goes to **review.collecting**, then
483
+ a development lap: requirements re-derived, the change amended
691
484
  - \`question\` — answered inline under the note in
692
485
  \`.gtd/REVIEW.md\` (**review.answer-review-questions**); the process
693
486
  rests at this gate again, no lap
@@ -1190,8 +983,7 @@ every commit is machine-authored.
1190
983
  .map((v) => v.slice(0, SIGNAL_LENGTH))
1191
984
  // A flag-on process with no tier mark fails closed, like an unreadable tier.
1192
985
  const risk =
1193
- tier === "high" ||
1194
- (tier === undefined && it.vars.flag_risk_tier === "1" && it.vars.flag_naive_pass === "1")
986
+ tier === "high" || (tier === undefined && it.vars.flag_risk_tier === "1")
1195
987
  ? "\nRisk tier: high — this merge needs a human reviewer (advisory, not enforced).\n"
1196
988
  : ""
1197
989
  // Signals land once, with the code that ships them; the risk advisory gates every merge.
@@ -1260,7 +1052,7 @@ Print the closing message and stop — this writes nothing itself.
1260
1052
  `
1261
1053
  }
1262
1054
 
1263
- // ── The seam phase (release flag `naive_pass`) ──────────────────────────────
1055
+ // ── The seam phase ──────────────────────────────────────────────────────────
1264
1056
 
1265
1057
  const listed = (paths: readonly string[], unreadable: readonly string[] = []): string =>
1266
1058
  paths
@@ -25,9 +25,7 @@ export const defaults: Readonly<Record<string, string>> = {
25
25
  reviewSeverityMinP: "0.7",
26
26
  refactorFlagPattern: "\\bGTD_FLAG_\\w+",
27
27
  seamAllow: [...testFileGlobs, ".gtd/**"].join(", "),
28
- // GTD_FLAG_NAIVE_PASS, recorded at process start; only "1" is on.
29
- flag_naive_pass: "0",
30
- // GTD_FLAG_RISK_TIER, recorded at process start; only "1" is on. Acts only with flag_naive_pass.
28
+ // GTD_FLAG_RISK_TIER, recorded at process start; only "1" is on.
31
29
  flag_risk_tier: "0",
32
30
  // Decides the turn count: one `build.quality.<lens>` scope per entry, each
33
31
  // keyed in `./skills.ts`.