devflow-kit 3.0.1 → 3.2.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 (166) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +1 -1
  3. package/dist/agents/git.md +2 -2
  4. package/dist/cli/agents-view/index.js +1 -1
  5. package/dist/cli/agents-view/render.js +71 -17
  6. package/dist/cli/agents-view/state.js +42 -16
  7. package/dist/cli/agents-view/terminal.js +5 -5
  8. package/dist/cli/commands/agents.js +142 -51
  9. package/dist/cli/commands/ambient.js +1 -1
  10. package/dist/cli/commands/attribution-prompts.js +8 -8
  11. package/dist/cli/commands/capture.js +1 -1
  12. package/dist/cli/commands/compliance-prompts.js +8 -8
  13. package/dist/cli/commands/compliance.js +8 -7
  14. package/dist/cli/commands/flags.js +33 -31
  15. package/dist/cli/commands/hud.js +1 -1
  16. package/dist/cli/commands/init-seed.js +9 -9
  17. package/dist/cli/commands/init.js +162 -85
  18. package/dist/cli/commands/install-report.js +10 -10
  19. package/dist/cli/commands/learning.js +302 -136
  20. package/dist/cli/commands/memory.js +36 -15
  21. package/dist/cli/commands/proxy.js +23 -23
  22. package/dist/cli/commands/rules.js +6 -5
  23. package/dist/cli/commands/tracker-prompts.js +6 -6
  24. package/dist/cli/commands/tracker.js +9 -9
  25. package/dist/cli/commands/uninstall.js +183 -59
  26. package/dist/cli/flags-view/render.js +5 -5
  27. package/dist/cli/flags-view/state.js +9 -9
  28. package/dist/cli/flags-view/terminal.js +4 -4
  29. package/dist/cli/tui/cells.js +1 -1
  30. package/dist/cli/tui/terminal.js +6 -6
  31. package/dist/commands/code-review.md +0 -2
  32. package/dist/commands/debug.md +14 -11
  33. package/dist/commands/dynamic-build.md +51 -47
  34. package/dist/commands/dynamic-plan.md +27 -7
  35. package/dist/commands/dynamic-profile.md +17 -3
  36. package/dist/commands/dynamic-tickets.md +18 -4
  37. package/dist/commands/explore.md +9 -3
  38. package/dist/commands/implement.md +20 -16
  39. package/dist/commands/plan.md +13 -9
  40. package/dist/commands/release.md +23 -3
  41. package/dist/commands/research.md +9 -3
  42. package/dist/commands/resolve.md +9 -12
  43. package/dist/commands/self-review.md +0 -2
  44. package/dist/core/agent-frontmatter.js +28 -3
  45. package/dist/core/agent-models.js +204 -42
  46. package/dist/core/agent-state.js +28 -6
  47. package/dist/core/ansi.js +2 -2
  48. package/dist/core/assets.js +1 -1
  49. package/dist/core/cache.js +7 -8
  50. package/dist/core/codex-auth-inspect.js +4 -4
  51. package/dist/core/compliance-compose.js +3 -3
  52. package/dist/core/compliance.js +3 -4
  53. package/dist/core/evidence-policy.js +14 -13
  54. package/dist/core/external-models.js +1 -1
  55. package/dist/core/feature-config.js +71 -13
  56. package/dist/core/feature-switch.js +3 -3
  57. package/dist/core/flags.js +49 -25
  58. package/dist/core/fs-atomic.js +6 -7
  59. package/dist/core/learning-queue-cleanup.js +16 -81
  60. package/dist/core/learning-store.js +61 -0
  61. package/dist/core/linked-path.js +46 -0
  62. package/dist/core/manifest.js +5 -5
  63. package/dist/core/mds-variants.js +13 -13
  64. package/dist/core/model-discovery.js +8 -8
  65. package/dist/core/observations.js +17 -101
  66. package/dist/core/orphan-sweep.js +4 -4
  67. package/dist/core/plugins.js +13 -8
  68. package/dist/core/project-paths.js +9 -13
  69. package/dist/core/proxy-log.js +8 -8
  70. package/dist/core/proxy-state.js +3 -3
  71. package/dist/core/queue-drain.js +31 -0
  72. package/dist/core/reference-sweep.js +6 -6
  73. package/dist/core/teammate-mode-cleanup.js +1 -1
  74. package/dist/core/tracker.js +14 -14
  75. package/dist/hud/colors.js +2 -2
  76. package/dist/hud/components/learning-counts.js +54 -22
  77. package/dist/hud/components/version-badge.js +1 -1
  78. package/dist/skills/git/references/pr/resolve-review-threads.md +2 -2
  79. package/dist/skills/git/references/tracker/github/create-release.md +2 -2
  80. package/dist/skills/git/references/tracker/jira/create-release.md +2 -2
  81. package/dist/skills/git/references/tracker/linear/create-release.md +2 -2
  82. package/dist/targets/claude-code/compliance-install.js +17 -15
  83. package/dist/targets/claude-code/hooks.js +2 -2
  84. package/dist/targets/claude-code/installer.js +59 -32
  85. package/dist/targets/claude-code/legacy.js +1 -1
  86. package/dist/targets/claude-code/post-install.js +135 -45
  87. package/dist/targets/claude-code/tracker-install.js +2 -2
  88. package/package.json +1 -1
  89. package/src/assets/agents/code.md +15 -21
  90. package/src/assets/agents/design.md +4 -2
  91. package/src/assets/agents/diagnose.md +3 -1
  92. package/src/assets/agents/evaluate.md +4 -0
  93. package/src/assets/agents/git.mds +2 -2
  94. package/src/assets/agents/knowledge.md +5 -3
  95. package/src/assets/agents/learning.md +281 -196
  96. package/src/assets/agents/research.md +3 -1
  97. package/src/assets/agents/review.md +5 -3
  98. package/src/assets/agents/scrutinize.md +5 -1
  99. package/src/assets/agents/simplify.md +4 -0
  100. package/src/assets/agents/skim.md +4 -2
  101. package/src/assets/agents/synthesize.md +6 -0
  102. package/src/assets/agents/test.md +18 -10
  103. package/src/assets/agents/triage.md +11 -9
  104. package/src/assets/agents/validate.md +14 -10
  105. package/src/assets/commands/_partials/_decisions.mds +8 -3
  106. package/src/assets/commands/_partials/_docs_root.mds +3 -3
  107. package/src/assets/commands/_partials/_engine.mds +16 -32
  108. package/src/assets/commands/_partials/_knowledge.mds +0 -2
  109. package/src/assets/commands/_partials/_preamble.mds +6 -2
  110. package/src/assets/commands/_partials/_settings.mds +2 -2
  111. package/src/assets/commands/_partials/_tracker.mds +1 -1
  112. package/src/assets/commands/code-review.mds +0 -2
  113. package/src/assets/commands/debug.mds +13 -8
  114. package/src/assets/commands/dynamic-build.mds +18 -12
  115. package/src/assets/commands/dynamic-plan.mds +10 -4
  116. package/src/assets/commands/dynamic-profile.mds +1 -1
  117. package/src/assets/commands/dynamic-tickets.mds +2 -2
  118. package/src/assets/commands/explore.mds +9 -1
  119. package/src/assets/commands/implement.mds +19 -13
  120. package/src/assets/commands/plan.mds +12 -8
  121. package/src/assets/commands/release.md +23 -3
  122. package/src/assets/commands/research.mds +9 -3
  123. package/src/assets/commands/resolve.mds +9 -10
  124. package/src/assets/mds/git/_pr.mds +3 -3
  125. package/src/assets/mds/tracker/_common.mds +1 -1
  126. package/src/assets/mds/tracker/_github.mds +3 -3
  127. package/src/assets/mds/tracker/_jira.mds +3 -3
  128. package/src/assets/mds/tracker/_linear.mds +3 -3
  129. package/src/assets/mds/tracker/_mcp.mds +6 -5
  130. package/src/assets/scripts/hooks/assets/orchestrator-charter.md +4 -2
  131. package/src/assets/scripts/hooks/background-memory-update +97 -33
  132. package/src/assets/scripts/hooks/capture-prompt +4 -3
  133. package/src/assets/scripts/hooks/capture-question +4 -3
  134. package/src/assets/scripts/hooks/capture-turn +5 -20
  135. package/src/assets/scripts/hooks/ensure-devflow-init +14 -2
  136. package/src/assets/scripts/hooks/ensure-proxy +5 -6
  137. package/src/assets/scripts/hooks/ensure-root-gitignore +123 -11
  138. package/src/assets/scripts/hooks/git-marker +71 -0
  139. package/src/assets/scripts/hooks/is-hex-sha +1 -1
  140. package/src/assets/scripts/hooks/json-helper.cjs +345 -944
  141. package/src/assets/scripts/hooks/json-parse +25 -129
  142. package/src/assets/scripts/hooks/lib/decisions-format.cjs +205 -156
  143. package/src/assets/scripts/hooks/lib/learning-store.cjs +3207 -0
  144. package/src/assets/scripts/hooks/lib/mkdir-lock.cjs +7 -5
  145. package/src/assets/scripts/hooks/lib/project-paths.cjs +13 -19
  146. package/src/assets/scripts/hooks/lib/render-decisions.cjs +253 -226
  147. package/src/assets/scripts/hooks/memory-worker +10 -0
  148. package/src/assets/scripts/hooks/pre-compact-memory +66 -14
  149. package/src/assets/scripts/hooks/preamble +9 -1
  150. package/src/assets/scripts/hooks/queue-append +55 -23
  151. package/src/assets/scripts/hooks/resolve-project-root +3 -4
  152. package/src/assets/scripts/hooks/session-start-context +146 -45
  153. package/src/assets/scripts/hooks/session-start-memory +33 -11
  154. package/src/assets/scripts/lib/project-config.cjs +2 -2
  155. package/src/assets/scripts/pr-evidence.cjs +3 -3
  156. package/src/assets/scripts/redact-secrets.cjs +20 -20
  157. package/src/assets/scripts/release-trace.cjs +1 -1
  158. package/src/assets/scripts/resolve-evidence-policy.cjs +3 -3
  159. package/src/assets/scripts/resolve-settings.cjs +3 -3
  160. package/src/assets/scripts/verify-evidence.cjs +2 -2
  161. package/src/assets/skills/apply-decisions/SKILL.md +37 -17
  162. package/src/assets/skills/docs-framework/SKILL.md +2 -2
  163. package/src/assets/skills/feature-knowledge/SKILL.md +6 -5
  164. package/src/assets/skills/test-driven-development/SKILL.md +6 -4
  165. package/dist/core/observation-io.js +0 -50
  166. package/src/assets/scripts/hooks/decisions-usage-scan.cjs +0 -131
@@ -79,7 +79,13 @@ Note the `budget` value from the Workflow tool context (or default to "medium" i
79
79
 
80
80
  **3. Detect mode: SINGLE or WAVE**
81
81
 
82
- - **SINGLE mode:** input is one ticket, one issue, one task description, or one plan document
82
+ What follows the command is bound once, here. Every later step names it `COMMAND_INPUT` and never restates it:
83
+
84
+ <command-input>
85
+ $ARGUMENTS
86
+ </command-input>
87
+
88
+ - **SINGLE mode:** `COMMAND_INPUT` is one ticket, one issue, one task description, or one plan document
83
89
  - **WAVE mode:** input is a set of tracker issues (wave labels, milestone, issue list), or the user says "wave" / "all tickets in wave N"
84
90
  - **A `/devflow:dynamic-tickets` ticket directory** (`{worktree}/.devflow/docs/tickets/{slug}/{ts}/`) is WAVE input: in each ticket file (every `.md` there but `tracking-issue.md`), the `**Issue:**` line directly after `**Depends on:**` is one raw `ISSUE_REFS` token, forwarded to the wave's pre-fetch verbatim — never rendered, normalised or re-derived. A ticket file with no `**Issue:**` line, or more than one, contributes no token; name it in the run summary as `not filed`.
85
91
 
@@ -113,7 +119,7 @@ If none found: build proceeds Gate-1-only (Gate 2 skipped with a note). Never re
113
119
  **5. Resolve tracking-issue number (optional)**
114
120
 
115
121
  Check, in priority order:
116
- - An explicit candidate issue reference or issue URL in the user's input (e.g. `#42`, `42`, or `https://github.com/…/issues/42`)
122
+ - An explicit candidate issue reference or issue URL in `COMMAND_INPUT` (e.g. `#42`, `42`, or `https://github.com/…/issues/42`)
117
123
  - The `**Issue:**` line directly after the H1 of the ticket set's `tracking-issue.md` (written by `/devflow:dynamic-tickets`' filing step; the file is at `{worktree}/.devflow/docs/tickets/{slug}/{ts}/tracking-issue.md`), as a raw token — only when the file holds exactly one `**Issue:**` line
118
124
  - Otherwise: none
119
125
 
@@ -194,7 +200,7 @@ ISSUE_NUMBER: ${ISSUE_NUMBER}
194
200
  ISSUE_PR_LINK: ${ISSUE_PR_LINK}
195
201
  COMPLIANCE_FRAMEWORKS: ${COMPLIANCE_FRAMEWORKS}
196
202
 
197
- When you build or run tests to verify your work, use your "Long-running commands" discipline (background-Bash + Monitor poll) for anything that may run silent >120s, and prefer package-scoped commands.
203
+ When you build or run tests to verify your work, follow your Running commands block.
198
204
 
199
205
  After implementing, commit your changes with a conventional-commit message and report:
200
206
  - Files changed
@@ -206,7 +212,7 @@ After implementing, commit your changes with a conventional-commit message and r
206
212
  const gate1 = await phase("gate1", async () => {
207
213
  // Gate 1 #1 — runs once, immediately after the initial implementation.
208
214
  const validation = await agent(`Run build, typecheck, lint, and tests on branch ${BRANCH}.
209
- For any build/test that may run silent >120s, use the background-Bash + Monitor poll procedure (your "Long-running commands" discipline) so you never trip the 180s watchdog; prefer package-scoped commands.
215
+ Follow your Running commands block for every build and test command.
210
216
  Report: PASS or FAIL with details.`, { agentType: "Validate" });
211
217
 
212
218
  if (validation.verdict === "FAIL") {
@@ -261,7 +267,7 @@ ${panel.filter(p => p.verdict === "FAIL").map(p => p.rationale).join("\n")}
261
267
  ISSUE_NUMBER: ${ISSUE_NUMBER}
262
268
  ISSUE_PR_LINK: ${ISSUE_PR_LINK}
263
269
  COMPLIANCE_FRAMEWORKS: ${COMPLIANCE_FRAMEWORKS}
264
- Self-verify your fix compiles (background-Bash + Monitor for any build >120s — see your "Long-running commands" discipline). Commit fixes.`, { agentType: "Code" });
270
+ Self-verify your fix compiles, following your Running commands block. Commit fixes.`, { agentType: "Code" });
265
271
  evalVerdict = "FAIL-FIXED"; // issues found, fixes applied, not re-evaluated by design
266
272
  }
267
273
  }
@@ -271,7 +277,7 @@ Self-verify your fix compiles (background-Bash + Monitor for any build >120s —
271
277
  const testResult = await agent(`Run scenario-based acceptance tests on branch ${BRANCH} against these criteria:
272
278
  ${CRITERIA || "(none)"}
273
279
  TEST_PLAN: ${TEST_PLAN || "(none)"}
274
- For any test/build command that may run silent >120s, use the background-Bash + Monitor poll procedure (your "Long-running commands" discipline) so you never trip the 180s watchdog.
280
+ Follow your Running commands block for every scenario command.
275
281
  Cover: functionality, API contracts, performance, and cover every TEST_PLAN scenario. Report: PASS or FAIL per scenario.`, { agentType: "Test" });
276
282
  testVerdict = testResult.verdict;
277
283
  if (testVerdict === "FAIL") {
@@ -281,7 +287,7 @@ ${testResult.failures}
281
287
  ISSUE_NUMBER: ${ISSUE_NUMBER}
282
288
  ISSUE_PR_LINK: ${ISSUE_PR_LINK}
283
289
  COMPLIANCE_FRAMEWORKS: ${COMPLIANCE_FRAMEWORKS}
284
- Self-verify your fix compiles and the scenarios pass (background-Bash + Monitor for any build/test >120s). Commit fixes.`, { agentType: "Code" });
290
+ Self-verify your fix compiles and the scenarios pass, following your Running commands block. Commit fixes.`, { agentType: "Code" });
285
291
  testVerdict = "FAIL-FIXED"; // issues found, fixes applied, not re-evaluated by design
286
292
  }
287
293
  }
@@ -395,7 +401,7 @@ ${chunk.map(f => `- ${f.description} (${f.severity})`).join("\n")}
395
401
  ISSUE_NUMBER: ${ISSUE_NUMBER}
396
402
  ISSUE_PR_LINK: ${ISSUE_PR_LINK}
397
403
  COMPLIANCE_FRAMEWORKS: ${COMPLIANCE_FRAMEWORKS}
398
- Fix all findings in this batch. Self-verify your fix compiles (background-Bash + Monitor for any build >120s — see your "Long-running commands" discipline). Commit with conventional-commit message.
404
+ Fix all findings in this batch. Self-verify your fix compiles, following your Running commands block. Commit with conventional-commit message.
399
405
  Return: {"status": "fixed"|"blocked", "commitShas": ["<sha>"], "unresolved": ["<description of any finding that could not be fixed>"]}`, { agentType: "Code" });
400
406
  chunkResults.push({ chunk, result: r });
401
407
  }
@@ -435,7 +441,7 @@ Return: {"status": "fixed"|"blocked", "commitShas": ["<sha>"], "unresolved": ["<
435
441
  // this is the build gate before the branch is handed back. See gate1_postcode() cadence.
436
442
  const gate1Final = await phase("gate1-final", async () => {
437
443
  const validation = await agent(`Run build, typecheck, lint, and tests on branch ${BRANCH} (final gate after all fixing).
438
- For any build/test that may run silent >120s, use the background-Bash + Monitor poll procedure (your "Long-running commands" discipline) so you never trip the 180s watchdog; prefer package-scoped commands.
444
+ Follow your Running commands block for every build and test command.
439
445
  Report: PASS or FAIL with details.`, { agentType: "Validate" });
440
446
 
441
447
  if (validation.verdict === "FAIL") {
@@ -447,7 +453,7 @@ ISSUE_NUMBER: ${ISSUE_NUMBER}
447
453
  ISSUE_PR_LINK: ${ISSUE_PR_LINK}
448
454
  COMPLIANCE_FRAMEWORKS: ${COMPLIANCE_FRAMEWORKS}
449
455
  Self-verify your fix compiles. Commit fixes with conventional-commit message.`, { agentType: "Code" });
450
- const recheck = await agent(`Re-run build, typecheck, lint, tests on branch ${BRANCH} (background+Monitor for long commands). Report: PASS or FAIL.`, { agentType: "Validate" });
456
+ const recheck = await agent(`Re-run build, typecheck, lint, tests on branch ${BRANCH} (follow your Running commands block). Report: PASS or FAIL.`, { agentType: "Validate" });
451
457
  if (recheck.verdict === "PASS") break;
452
458
  failureDetails = recheck.details || failureDetails;
453
459
  if (attempt === 2) return { verdict: "ESCALATED", reason: "Final Gate 1 validation exhausted after 2 Code agent fix attempts" };
@@ -459,7 +465,7 @@ Self-verify your fix compiles. Commit fixes with conventional-commit message.`,
459
465
  const scrutiny = await agent(`9-pillar self-review of recent changes on branch ${BRANCH}. Report any code you changed and your findings.`, { agentType: "Scrutinize" });
460
466
 
461
467
  if (scrutiny.codeChanged) {
462
- await agent(`Re-run build, typecheck, lint, tests on branch ${BRANCH} (Scrutinize agent made changes; background+Monitor for long commands). Report: PASS or FAIL.`, { agentType: "Validate" });
468
+ await agent(`Re-run build, typecheck, lint, tests on branch ${BRANCH} (Scrutinize agent made changes; follow your Running commands block). Report: PASS or FAIL.`, { agentType: "Validate" });
463
469
  }
464
470
 
465
471
  return { verdict: "PASS" };
@@ -739,4 +745,4 @@ Update the wave PR's test-plan block and post its evidence comment."
739
745
 
740
746
  ### Maintenance note
741
747
 
742
- This recipe encodes the current `/implement` + `/code-review` + `/resolve` orchestration shape as of the authoring date (2026-06-12). When those base commands change their orchestration, update this recipe to match. No tooling detects drift — by design (ADR-008 Iron Rule). The reminder lives in the design doc §16.
748
+ This recipe encodes the current `/implement` + `/code-review` + `/resolve` orchestration shape as of the authoring date (2026-06-12). When those base commands change their orchestration, update this recipe to match. No tooling detects drift — by design (the LLM-vs-plumbing Iron Rule). The reminder lives in the design doc §16.
@@ -59,7 +59,13 @@ If present, note its contents as `PREFERENCE_PROFILE`. This will be used to auto
59
59
 
60
60
  **3. Resolve ticket input**
61
61
 
62
- Determine the ticket source (in priority order):
62
+ What follows the command is bound once, here. Every later step names it `COMMAND_INPUT` and never restates it:
63
+
64
+ <command-input>
65
+ $ARGUMENTS
66
+ </command-input>
67
+
68
+ Determine the ticket source from `COMMAND_INPUT` (in priority order):
63
69
  - A directory of ticket `.md` files (from `/devflow:dynamic-tickets` output)
64
70
  - A list of candidate issue references or issue URLs
65
71
  - Inline ticket descriptions passed as args
@@ -127,7 +133,7 @@ const plans = await phase("plan-parallel", () =>
127
133
  parallel((tickets || []).map(ticket => () =>
128
134
  agent(`Write an implementation plan for this ticket.
129
135
  Ticket: ${JSON.stringify(ticket)}
130
- Decisions context (apply devflow:apply-decisions; cite ADR/PF IDs): ${DECISIONS_CONTEXT}
136
+ Decisions context (apply devflow:apply-decisions; a plan file can be posted to the tracker, so state each decision in words, never by ID): ${DECISIONS_CONTEXT}
131
137
  The plan must cover: approach overview, affected files and modules, key design decisions, implementation sequence (what to build first), risks and mitigations, and any open questions you cannot resolve from the ticket alone.
132
138
  Write a thorough but tight plan — every section must earn its place for a Code agent who has no other context.
133
139
  Return: { ticketTitle, planMarkdown, openDecisions (array of genuine unknowns requiring user input) }.`, { agentType: "Design" })
@@ -218,7 +224,7 @@ For each ticket, write ${OUTDIR}/{ticket-slug}-plan.md containing:
218
224
  - ## Acceptance Criteria (numbered, positive + negative)
219
225
  - ## Test Plan — the challenger's testPlan lines, verbatim, one per line, and nothing else: no prose, no blank line between them, no setup or outcome
220
226
  - ## Test Scenarios — one line per TP, in TP order: TP-n: its setup, then its expected outcome, from testScenarios
221
- - ## Auto-Resolved Decisions (if any — list each as: decision → resolution → source)
227
+ - ## Auto-Resolved Decisions (if any — list each as: decision → resolution → source, naming a recorded decision in words, never by ID)
222
228
 
223
229
  Then write ${OUTDIR}/DECISIONS-NEEDED.md:
224
230
  - ## Auto-Resolved Decisions — list each silently-resolved decision as: decision → resolution → source (preference profile / ADR-NNN), so auto-resolution is auditable and reversible. If none, write "None."
@@ -268,4 +274,4 @@ After the workflow returns: check each plan's test plan (step 1 of the F4 list a
268
274
 
269
275
  ### Maintenance note
270
276
 
271
- This recipe encodes the planning pipeline as of the authoring date (2026-06-12). The plan-challenge verbatim intent (§5.1) is load-bearing — do not paraphrase it when authoring the challenger agent prompt. The "Acceptance criteria + test plan contract" section above is the shared shape with `/devflow:dynamic-build` Gate 2; any change must be kept in sync. No tooling detects drift — by design (ADR-008 Iron Rule).
277
+ This recipe encodes the planning pipeline as of the authoring date (2026-06-12). The plan-challenge verbatim intent (§5.1) is load-bearing — do not paraphrase it when authoring the challenger agent prompt. The "Acceptance criteria + test plan contract" section above is the shared shape with `/devflow:dynamic-build` Gate 2; any change must be kept in sync. No tooling detects drift — by design (the LLM-vs-plumbing Iron Rule).
@@ -142,4 +142,4 @@ Next steps:
142
142
 
143
143
  ### Maintenance note
144
144
 
145
- This command mines ALL projects' history on this machine. The bounded-reading discipline (grep/rg + sample — never full-read) is mandatory and must be preserved in every revision. The agent writes prose; no extraction or clustering algorithm is authored here. Per ADR-008 Iron Rule: the agent does the reading and summarizing — not a script we maintain.
145
+ This command mines ALL projects' history on this machine. The bounded-reading discipline (grep/rg + sample — never full-read) is mandatory and must be preserved in every revision. The agent writes prose; no extraction or clustering algorithm is authored here. Per the LLM-vs-plumbing Iron Rule: the agent does the reading and summarizing — not a script we maintain.
@@ -105,7 +105,7 @@ const drafts = await phase("draft", () =>
105
105
  agent(`Draft ticket for initiative: "${initiative}"
106
106
  Ticket: ${JSON.stringify(c)}
107
107
  Constraints: ${constraints}
108
- Decisions context (apply devflow:apply-decisions; cite ADR/PF IDs): ${DECISIONS_CONTEXT}
108
+ Decisions context (apply devflow:apply-decisions; the ticket is filed to the tracker, so state each decision in words, never by ID): ${DECISIONS_CONTEXT}
109
109
  Write the ticket body following the ticket_body_template structure (Wave/Depends-on header, Summary, Scope with In/Out + anti-features, Invariants, numbered Acceptance Criteria with at least one negative criterion, Open Questions).
110
110
  Return a JSON object with: title (string), summary (string), wave (number), dependsOn (array), bodyMarkdown (string), openQuestions (array).`, { agentType: "Design" })
111
111
  ))
@@ -270,4 +270,4 @@ The tracking-issue path and any open questions are the primary handoff to `/devf
270
270
 
271
271
  ### Maintenance note
272
272
 
273
- This recipe encodes the ticket-factory shape as of the authoring date (2026-06-12). The pipeline structure (`draft → [2-lens review] → revise → whole-set critic → amend → tracking-issue`) is the load-bearing invariant. Per ADR-008, no deterministic ticket-parsing logic is added — ticket slates are proposed by the model and confirmed by the user. When the devflow agent roster changes, update the `agentType` values above. No tooling detects drift — by design (ADR-008 Iron Rule).
273
+ This recipe encodes the ticket-factory shape as of the authoring date (2026-06-12). The pipeline structure (`draft → [2-lens review] → revise → whole-set critic → amend → tracking-issue`) is the load-bearing invariant. Per the LLM-vs-plumbing Iron Rule, no deterministic ticket-parsing logic is added — ticket slates are proposed by the model and confirmed by the user. When the devflow agent roster changes, update the `agentType` values above. No tooling detects drift — by design, under the same rule.
@@ -18,7 +18,13 @@ Explore a codebase area by spawning parallel agents for flow tracing, dependency
18
18
 
19
19
  ## Input
20
20
 
21
- `$ARGUMENTS` contains whatever follows `/explore`:
21
+ What follows `/explore` is bound once, here. Every later step names it `COMMAND_INPUT` and never restates it:
22
+
23
+ <command-input>
24
+ $ARGUMENTS
25
+ </command-input>
26
+
27
+ `COMMAND_INPUT` is one of:
22
28
  - Area description: "how does the auth system work"
23
29
  - Flow question: "trace the request lifecycle"
24
30
  - Empty: use conversation context
@@ -58,6 +64,8 @@ Based on Skim agent findings, spawn 2-3 `Agent(subagent_type="Explore")` agents
58
64
 
59
65
  Adjust explorer focus based on the specific exploration question.
60
66
 
67
+ Ask each explorer for a final report of at most about 1,500 tokens: findings with file:line references, not file dumps.
68
+
61
69
  ### Phase 4: Synthesize
62
70
 
63
71
  **Produces:** MERGED_FINDINGS
@@ -25,7 +25,13 @@ Orchestrate a single task through implementation by spawning specialized agents.
25
25
 
26
26
  ## Input
27
27
 
28
- `$ARGUMENTS` contains whatever follows `/implement`:
28
+ What follows `/implement` is bound once, here. Every later step names it `COMMAND_INPUT` and never restates it:
29
+
30
+ <command-input>
31
+ $ARGUMENTS
32
+ </command-input>
33
+
34
+ `COMMAND_INPUT` is one of:
29
35
  - Plan document path: `.devflow/docs/design/42-jwt-auth.2026-04-07_1430.md` (path to an existing `.md` file)
30
36
  - Issue reference: `#42`
31
37
  - Task description: "implement JWT auth"
@@ -53,15 +59,13 @@ If the user prompt does NOT match re-validation, proceed with the full pipeline
53
59
 
54
60
  **Produces:** TASK_ID, BASE_BRANCH, EXECUTION_PLAN, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, PR_DESCRIPTION_GUIDANCE, ISSUE_NUMBER, EVIDENCE_POLICY, ISSUE_REQUIRED, APPLY_CONVENTIONS, REQUIRE_NON_AUTHOR_APPROVAL, PR_EXCEPTIONS, TEST_PLAN, EVIDENCE_FILE, PR_TEST_PLAN_BLOCK, REVIEW_PUBLICATION
55
61
 
56
- **Load Companion Skills** — Load via Skill tool: `devflow:test-driven-development`, `devflow:patterns`, `devflow:dependency-research`. If a skill fails to load, continue without it.
57
-
58
62
  Record the current branch name as `BASE_BRANCH` - this will be the PR target.
59
63
 
60
64
  {{docs_root()}}
61
65
 
62
66
  {{evidence_policy()}}
63
67
 
64
- **Plan Document Handling** (when $ARGUMENTS is a path ending in `.md`):
68
+ **Plan Document Handling** (when `COMMAND_INPUT` is a path ending in `.md`):
65
69
  1. Read the plan document from the path provided
66
70
  2. Extract from YAML frontmatter: `execution-strategy`, `context-risk`, `issue` number
67
71
  3. Extract from body: Subtask Breakdown, Implementation Plan, Patterns to Follow, Acceptance Criteria
@@ -72,23 +76,25 @@ Record the current branch name as `BASE_BRANCH` - this will be the PR target.
72
76
 
73
77
  If `PR_DESCRIPTION_GUIDANCE` was not set above (non-plan paths: issue input or task description), set it to `(none)`.
74
78
 
79
+ **Empty input.** When `COMMAND_INPUT` is empty — a plan handoff arrives this way, with the plan already in the conversation — there is no argument to name the branch from, and the Git agent sees none of this conversation. Write the description yourself: one line, taken from the plan's title or, with no plan, from the conversation. Send it as the setup-task `TASK_DESCRIPTION` below.
80
+
75
81
  Spawn Git agent to set up task environment. The Git agent derives the branch name automatically from the issue or task description:
76
82
 
77
83
  ```
78
84
  Agent(subagent_type="Git"):
79
85
  "OPERATION: setup-task
80
86
  BASE_BRANCH: {current branch name}
81
- ISSUE_INPUT: {$ARGUMENTS verbatim, when it is a single whitespace-delimited token that does not end in .md; when it ends in .md, the plan frontmatter's issue value verbatim unless absent or pending — otherwise omit}
82
- TASK_DESCRIPTION: {$ARGUMENTS verbatim, when it is two or more whitespace-delimited tokens — otherwise omit}
87
+ ISSUE_INPUT: {COMMAND_INPUT verbatim, when it is a single whitespace-delimited token that does not end in .md; when it ends in .md, the plan frontmatter's issue value verbatim unless absent or pending — otherwise omit}
88
+ TASK_DESCRIPTION: {COMMAND_INPUT verbatim, when it is two or more whitespace-delimited tokens; when COMMAND_INPUT is empty, the one-line description you wrote above — otherwise omit}
83
89
  ISSUE_REQUIRED: {ISSUE_REQUIRED}
84
90
  APPLY_CONVENTIONS: {APPLY_CONVENTIONS}
85
- PLAN_ARTIFACT_PATH: {path to plan document if $ARGUMENTS ends in .md, otherwise (none)}
91
+ PLAN_ARTIFACT_PATH: {path to plan document if COMMAND_INPUT ends in .md, otherwise (none)}
86
92
  Derive branch name from issue or description, create feature branch, and fetch issue if specified.
87
93
  Return the branch setup summary."
88
94
  ```
89
95
 
90
96
  The issue token is forwarded **unclassified**, and the routing is decided by
91
- SHAPE alone — how many tokens `$ARGUMENTS` has, and whether it ends in `.md`.
97
+ SHAPE alone — how many tokens `COMMAND_INPUT` has, and whether it ends in `.md`.
92
98
 
93
99
  `setup-task` is the one step that has resolved a provider, and therefore the only
94
100
  one that knows what an issue reference looks like on this machine: `#123`,
@@ -133,7 +139,7 @@ visible, a silently discarded request is not.
133
139
 
134
140
  **Test plan.** Before any Code spawn, give the task a test plan in the evidence file `{worktree}/.devflow/docs/evidence-{branch_slug}.md` (`EVIDENCE_FILE`) — unlike the handoff file, it stays after the PR exists. It holds up to three sections, in this order and nothing else: `## Test Plan`; `## Evidence Exceptions`, a byte copy of `PR_EXCEPTIONS` present only while that is not `(none)`; and `## Claims`, always last, so every claim is appended at the end of the file. Create the file if absent; if it exists, replace its `## Test Plan` and `## Evidence Exceptions` sections and keep `## Claims` byte-identical.
135
141
 
136
- Write the `## Test Plan` section: when `$ARGUMENTS` is a plan document with a `## Test Plan` section, copy that section's lines verbatim; otherwise write one TP line per acceptance criterion the plan, the issue or the task text states, numbered from `TP-1`. Never invent a criterion, and word every scenario yourself in plain words: the lines reach the PR body, so a scenario holds no `#`, `@` or `/` — no issue reference, mention, closing keyword target or URL — and the files a TP covers go in its `files:` field. Each line follows the TP-line contract:
142
+ Write the `## Test Plan` section: when `COMMAND_INPUT` is a plan document with a `## Test Plan` section, copy that section's lines verbatim; otherwise write one TP line per acceptance criterion the plan, the issue or the task text states, numbered from `TP-1`. Never invent a criterion, and word every scenario yourself in plain words: the lines reach the PR body, so a scenario holds no `#`, `@` or `/` — no issue reference, mention, closing keyword target or URL — and the files a TP covers go in its `files:` field. Each line follows the TP-line contract:
137
143
 
138
144
  {{test_plan_line()}}
139
145
 
@@ -314,7 +320,7 @@ ISSUE_PR_LINK: {ISSUE_PR_LINK captured in Phase 1, or (none)}"
314
320
  After Code agent completes, spawn Validate agent to verify correctness:
315
321
 
316
322
  ```
317
- Agent(subagent_type="Validate", model="haiku"):
323
+ Agent(subagent_type="Validate"):
318
324
  "FILES_CHANGED: {list of files from Code agent output}
319
325
  VALIDATION_SCOPE: full
320
326
  Run build, typecheck, lint, test. Report pass/fail with failure details."
@@ -394,7 +400,7 @@ If Scrutinize agent returns BLOCKED, report to user and halt.
394
400
  If Scrutinize agent made code changes (status: FIXED), spawn Validate agent to verify:
395
401
 
396
402
  ```
397
- Agent(subagent_type="Validate", model="haiku"):
403
+ Agent(subagent_type="Validate"):
398
404
  "FILES_CHANGED: {files modified by Scrutinize agent}
399
405
  VALIDATION_SCOPE: changed-only
400
406
  Verify Scrutinize agent's fixes didn't break anything."
@@ -442,7 +448,7 @@ Validate alignment with request and plan. Report ALIGNED or MISALIGNED with deta
442
448
  ```
443
449
  - Spawn Validate agent to verify fix didn't break tests:
444
450
  ```
445
- Agent(subagent_type="Validate", model="haiku"):
451
+ Agent(subagent_type="Validate"):
446
452
  "FILES_CHANGED: {files modified by fix Code agent}
447
453
  VALIDATION_SCOPE: changed-only"
448
454
  ```
@@ -490,7 +496,7 @@ After every Test agent run — PASS or FAIL, first run or retry — append its T
490
496
  ```
491
497
  - Spawn Validate agent to verify fix didn't break tests:
492
498
  ```
493
- Agent(subagent_type="Validate", model="haiku"):
499
+ Agent(subagent_type="Validate"):
494
500
  "FILES_CHANGED: {files modified by fix Code agent}
495
501
  VALIDATION_SCOPE: changed-only"
496
502
  ```
@@ -26,7 +26,13 @@ The orchestrator only spawns agents and gates — all analytical work is done by
26
26
 
27
27
  ## Input
28
28
 
29
- `$ARGUMENTS` contains whatever follows `/plan`:
29
+ What follows `/plan` is bound once, here. Every later step names it `COMMAND_INPUT` and never restates it:
30
+
31
+ <command-input>
32
+ $ARGUMENTS
33
+ </command-input>
34
+
35
+ `COMMAND_INPUT` is one of:
30
36
  - Opens with a candidate issue reference → issue mode (one candidate = single-ref, more than one = multi-issue)
31
37
  - Path to existing `.md` file → **error**: "Use /implement with plan documents"
32
38
  - Other text → feature description
@@ -66,7 +72,7 @@ Explore the user's intent through focused Socratic questioning before spawning a
66
72
 
67
73
  **Step 0 — Fetch issue(s)** (issue mode only; skip for feature-description and empty modes):
68
74
 
69
- - **Single-ref** (one candidate ref in `$ARGUMENTS`):
75
+ - **Single-ref** (one candidate ref in `COMMAND_INPUT`):
70
76
 
71
77
  ```
72
78
  Agent(subagent_type="Git"):
@@ -106,8 +112,6 @@ If the user says "skip" or "just proceed" — skip remaining questions, present
106
112
  **Produces:** SKIM_CONTEXT, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE
107
113
  **Requires:** CONFIRMED_SCOPE
108
114
 
109
- **Load Companion Skills** — Load via Skill tool: `devflow:test-driven-development`, `devflow:patterns`, `devflow:software-design`, `devflow:security`, `devflow:design-review`. If a skill fails to load, continue without it.
110
-
111
115
  Spawn Skim agent for codebase context:
112
116
 
113
117
  ```
@@ -136,7 +140,7 @@ Pass `FEATURE_KNOWLEDGE` alongside `DECISIONS_CONTEXT` to Explore and Design age
136
140
  **Produces:** EXPLORE_OUTPUTS
137
141
  **Requires:** SKIM_CONTEXT, DECISIONS_CONTEXT
138
142
 
139
- Spawn 4 Explore agents **in a single message**, each with Skim agent context, `DECISIONS_CONTEXT` (from Phase 2), and `FEATURE_KNOWLEDGE` (from Phase 2). Include instructions: "follow `devflow:apply-decisions` for DECISIONS_CONTEXT" and "The FEATURE_KNOWLEDGE is a baseline — VALIDATE, EXTEND, and CORRECT it, don't repeat it. Focus on areas the feature knowledge doesn't cover and changes since it was last updated."
143
+ Spawn 4 Explore agents **in a single message**, each with Skim agent context, `DECISIONS_CONTEXT` (from Phase 2), and `FEATURE_KNOWLEDGE` (from Phase 2). Include instructions: "follow `devflow:apply-decisions` for DECISIONS_CONTEXT" and "The FEATURE_KNOWLEDGE is a baseline — VALIDATE, EXTEND, and CORRECT it, don't repeat it. Focus on areas the feature knowledge doesn't cover and changes since it was last updated." Ask each agent for a final report of at most about 1,500 tokens: findings with file:line references, not file dumps.
140
144
 
141
145
  | Focus | Thoroughness | Find |
142
146
  |-------|-------------|------|
@@ -265,7 +269,7 @@ User can:
265
269
  **Produces:** IMPL_EXPLORE_OUTPUTS
266
270
  **Requires:** SKIM_CONTEXT, ACCEPTED_SCOPE
267
271
 
268
- Spawn 4 Explore agents **in a single message**, each with Skim agent context + accepted scope:
272
+ Spawn 4 Explore agents **in a single message**, each with Skim agent context + accepted scope. Ask each agent for a final report of at most about 1,500 tokens: findings with file:line references, not file dumps.
269
273
 
270
274
  | Focus | Thoroughness | Find |
271
275
  |-------|-------------|------|
@@ -294,7 +298,7 @@ Combine into: patterns to follow, integration points, reusable code, edge cases"
294
298
  **Produces:** PLAN_OUTPUTS
295
299
  **Requires:** IMPL_EXPLORATION_SYNTHESIS, GAP_SYNTHESIS, DECISIONS_CONTEXT
296
300
 
297
- Spawn 3 Plan agents **in a single message**, each with implementation exploration synthesis:
301
+ Spawn 3 Plan agents **in a single message**, each with implementation exploration synthesis. Ask each agent for a final report of at most about 1,500 tokens: the plan itself, not a restatement of the exploration.
298
302
 
299
303
  | Focus | Output |
300
304
  |-------|--------|
@@ -470,7 +474,7 @@ Spawn a Git agent with `OPERATION: ensure-traceable-issue`:
470
474
  ```
471
475
  Agent(subagent_type="Git"):
472
476
  "OPERATION: ensure-traceable-issue
473
- ISSUE_INPUT: {the raw candidate token from $ARGUMENTS if /plan was invoked with an issue reference, else omit}
477
+ ISSUE_INPUT: {the raw candidate token from COMMAND_INPUT if /plan was invoked with an issue reference, else omit}
474
478
  TASK_DESCRIPTION: {Gate 0 confirmed scope — one-line title}
475
479
  INITIAL_REQUEST: {the Gate 0 confirmed scope statement}
476
480
  REQUIREMENTS: {discovered requirements summary from Phase 6 gap synthesis}
@@ -17,13 +17,19 @@ Release the project using adaptive learned configuration. On first run, scans th
17
17
 
18
18
  ## Input
19
19
 
20
- `$ARGUMENTS` contains whatever follows `/release`:
20
+ What follows `/release` is bound once, here. Every later step names it `COMMAND_INPUT` and never restates it:
21
+
22
+ <command-input>
23
+ $ARGUMENTS
24
+ </command-input>
25
+
26
+ `COMMAND_INPUT` is one of:
21
27
  - Explicit version: `v1.2.3` or `1.2.3`
22
28
  - Bump type: `patch`, `minor`, `major`
23
29
  - Flag: `--dry-run`
24
30
  - Empty: interactive mode (will ask for version)
25
31
 
26
- Parse from $ARGUMENTS:
32
+ Parse from `COMMAND_INPUT`:
27
33
  - `VERSION`: explicit version string if present (strip leading `v`)
28
34
  - `BUMP_TYPE`: `patch | minor | major` if bump type provided
29
35
  - `DRY_RUN`: true if `--dry-run` present, false otherwise
@@ -48,7 +54,21 @@ Read `.release/RELEASE-FLOW.md`:
48
54
 
49
55
  **Produces:** DECISIONS_CONTEXT, FEATURE_KNOWLEDGE
50
56
 
51
- Read `.devflow/learning/index.md`. If the file is absent or empty, set `DECISIONS_CONTEXT` to `(none)`; otherwise use the file content as `DECISIONS_CONTEXT`.
57
+ The decisions ledger belongs to the repository, not to one checkout: in a linked worktree it lives in the main worktree, and a session started in a subdirectory reads the copy at the repository root. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
58
+
59
+ ```bash
60
+ git -C "{start}" rev-parse --path-format=absolute --show-toplevel --git-common-dir
61
+ ```
62
+
63
+ Line 1 is the checkout's toplevel, line 2 the repository's common git directory. A git older than 2.31 echoes `--path-format=absolute` back as a line of its own first. `{ledger}` is the first of these that applies:
64
+
65
+ 1. **The main worktree** — line 2 without its trailing `/.git`, when the output is exactly two lines each beginning with `/`, line 2 ends in `/.git`, and the directory left once it is removed is not your home directory and contains a `.devflow/` directory.
66
+ 2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
67
+ 3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
68
+
69
+ This is the rule the learning hooks apply (D-LEDGER-MAIN-WORKTREE, D-PROMPT-ROOT), so you read the index the Learning agent writes.
70
+
71
+ Read `{ledger}/.devflow/learning/index.md`. If the file is absent or empty, set `DECISIONS_CONTEXT` to `(none)`; otherwise use the file content as `DECISIONS_CONTEXT`.
52
72
 
53
73
  Load feature knowledge: Attempt to read `.devflow/features/index.md` (the regenerable cache). If absent or empty, glob `.devflow/features/*/KNOWLEDGE.md` and read each file's YAML frontmatter (`name`, `description`, `directories`) as the relevance surface. Pick release-relevant KBs by matching their documented area against the release context. For each selected KB, read the full `KNOWLEDGE.md` — trust current code over KB content on any mismatch. Concatenate under slug headers and set `FEATURE_KNOWLEDGE` (or `(none)` if no KBs exist or none are relevant). No `index.json`, no subprocess, no `.cjs` script.
54
74
 
@@ -20,7 +20,13 @@ Research a topic by spawning parallel Research agents across multiple research t
20
20
 
21
21
  ## Input
22
22
 
23
- `$ARGUMENTS` contains whatever follows `/research`:
23
+ What follows `/research` is bound once, here. Every later step names it `COMMAND_INPUT` and never restates it:
24
+
25
+ <command-input>
26
+ $ARGUMENTS
27
+ </command-input>
28
+
29
+ `COMMAND_INPUT` is one of:
24
30
  - Research question: "best caching strategies"
25
31
  - Comparison question: "compare React vs Svelte for our use case"
26
32
  - Empty: use conversation context
@@ -35,7 +41,7 @@ Research a topic by spawning parallel Research agents across multiple research t
35
41
 
36
42
  {{decisions_load()}}
37
43
 
38
- Use `DECISIONS_CONTEXT` locally when framing research — prior decisions and pitfalls suggest areas to investigate. Follow `devflow:apply-decisions` to Read full entry bodies on demand. Pass `DECISIONS_CONTEXT` to each Research agent in Phase 4 so they can cite relevant decisions in findings.
44
+ Use `DECISIONS_CONTEXT` locally when framing research — prior decisions and pitfalls suggest areas to investigate. Follow `devflow:apply-decisions` to Read full entry bodies on demand. Pass `DECISIONS_CONTEXT` to each Research agent in Phase 4 so their findings can account for relevant decisions.
39
45
 
40
46
  {{knowledge_load()}}
41
47
 
@@ -111,7 +117,7 @@ If external research was skipped due to tool unavailability: inform user.
111
117
  1. If `codebase` type was not in RESEARCH_PLAN → skip
112
118
  2. Check if matching feature knowledge already exists by reading `{worktree}/.devflow/features/index.md` (or globbing frontmatter if absent). If covered → skip
113
119
  3. Use AskUserQuestion: "No feature knowledge exists for {researched area}. Create one?"
114
- 4. If user accepts: spawn `Agent(subagent_type="Knowledge")` with researched area context + worktree root, instructing it to load `devflow:feature-knowledge`, write `KNOWLEDGE.md`, and update `index.md` directly
120
+ 4. If user accepts: spawn `Agent(subagent_type="Knowledge")` with researched area context + worktree root, instructing it to write `KNOWLEDGE.md` and update `index.md` directly
115
121
  5. Set FEATURE_KNOWLEDGE_STATUS = created or skipped
116
122
 
117
123
  **Failure handling**: Non-blocking. If Knowledge agent fails, log and continue.
@@ -180,14 +180,14 @@ Wait for Triage agent to complete before proceeding. Parse verdict ledger from T
180
180
  - **ESCALATED**: Security issues requiring human escalation
181
181
  - **FIX_NOW**: Valid issues assigned to Code agents (with risk tier: Standard | Careful)
182
182
  - **FALSE_POSITIVE**: Issues the Review agent got wrong (with cited evidence)
183
- - **BY_DESIGN**: Intentional code (with ADR or code doc citation)
183
+ - **BY_DESIGN**: Intentional code (with a recorded decision, stated in words, or a code doc citation)
184
184
  - **FIX_SEPARATE**: Valid but out of blast-radius scope (must become manage-debt ticket)
185
185
  - **TECH_DEBT**: Architectural overhaul only — LAST RESORT
186
186
  - **DUPLICATE**: Collapsed duplicate issue — carries `duplicate_of: <primary-id>` referencing the non-DUPLICATE primary; inherits the primary's outcome
187
187
 
188
- Collect all decisions citations (ADR-NNN / PF-NNN) from Triage agent Reasoning columns.
188
+ Collect every decision and pitfall the Triage agent's Reasoning columns state, in its words — the resolution summary is posted, so it never carries an ADR/PF ID.
189
189
 
190
- **Triage agent completeness assertion (avoids PF-002):** Verify the parsed ledger against ISSUES before proceeding:
190
+ **Triage agent completeness assertion:** Verify the parsed ledger against ISSUES before proceeding:
191
191
  1. Every issue `id` from ISSUES must appear in exactly one verdict bucket — none may vanish, none may appear in multiple buckets. DUPLICATE is a valid bucket; a valid DUPLICATE entry must name its `duplicate_of` primary (the `Duplicate Of` column of the ledger's DUPLICATE table) and that primary must be a non-DUPLICATE issue id. A missing `duplicate_of` or one that chains to another DUPLICATE is a **Triage agent failure** (retry-then-abort as below).
192
192
  2. If the Triage agent output is empty, contains a skill re-entrancy guard string (e.g., contains `already running`), or is missing any issue IDs from ISSUES: treat as a **Triage agent failure**:
193
193
  - Retry the Triage agent once with the same inputs.
@@ -275,7 +275,7 @@ If no fixes were made (CODE_AGENT_RESULTS contains 0 commits) → set VERIFICATI
275
275
  Otherwise, spawn Validate agent:
276
276
 
277
277
  ```
278
- Agent(subagent_type="Validate", model="haiku"):
278
+ Agent(subagent_type="Validate"):
279
279
  "FILES_CHANGED: {list of files from Code agent output}
280
280
  VALIDATION_SCOPE: full
281
281
  Run build, typecheck, lint, test. Report pass/fail with failure details."
@@ -401,7 +401,7 @@ Run this step only when `EVIDENCE_POLICY` is `required` and THREAD_MAP is non-em
401
401
 
402
402
  Prepare THREAD_MAP with verdicts from triage/code agent results:
403
403
  - For each `ext-{N}`: match to an issue verdict (FIXED, FALSE_POSITIVE, BY_DESIGN, ESCALATED) by `file:line` correlation
404
- - If the matched issue has verdict DUPLICATE, use the **primary's** verdict and verification status for the reply — do not expose DUPLICATE to the thread author (avoids PF-024; caller-side mapping — git.md contracts unchanged)
404
+ - If the matched issue has verdict DUPLICATE, use the **primary's** verdict and verification status for the reply — do not expose DUPLICATE to the thread author (caller-side mapping: the Git agent's verdict set has no DUPLICATE, so its contract stays unchanged)
405
405
  - Include `commit_sha` from Code agent results for FIXED verdicts
406
406
  - If `fork_no_push` is set: drop FIXED entries from THREAD_MAP — their commits never reached the PR — and record each as `DEGRADED` in `## Third-Party Threads`
407
407
  - Unmatched threads: ESCALATED (human review)
@@ -642,8 +642,7 @@ Written in Phase 5 (Collect Results) to `{TARGET_DIR}/resolution-summary.md`:
642
642
 
643
643
  ## Decisions Citations
644
644
 
645
- - applies ADR-{NNN} — {batch-id}, {issue-id}
646
- - avoids PF-{NNN} — {batch-id}, {issue-id}
645
+ - {decision applied or pitfall avoided, stated in words — never its ID} — {batch-id}, {issue-id}
647
646
 
648
647
  (Omit section if no citations were made)
649
648
 
@@ -681,9 +680,9 @@ Final gate: PASS | FAILED after {n} attempts
681
680
  | {description} | {file}:{line} | {why} |
682
681
 
683
682
  ## By Design
684
- | Issue | File:Line | Rationale (ADR/doc) |
685
- |-------|-----------|---------------------|
686
- | {description} | {file}:{line} | {applies ADR-NNN or code comment} |
683
+ | Issue | File:Line | Rationale (decision/doc) |
684
+ |-------|-----------|--------------------------|
685
+ | {description} | {file}:{line} | {the decision, in words, or code comment} |
687
686
 
688
687
  ## Fix Separately
689
688
  | Issue | File:Line | Reason | Tracked |
@@ -35,7 +35,7 @@ omission:
35
35
  Headings below each section's own anchor are `###` by grammar, not by taste: a
36
36
  column-0 `## ` line outside a fence terminates the section for every guard that
37
37
  reads it through `extractOpSectionFromCorpus`, and everything under it becomes
38
- invisible while the bytes stay on disk (PF-063). The `## ` lines inside the two
38
+ invisible while the bytes stay on disk. The `## ` lines inside the two
39
39
  summary operations' compose fences are indented payload and stay exactly as they
40
40
  were authored.
41
41
 
@@ -186,7 +186,7 @@ Load for `resolve-review-threads` under every tracker provider.
186
186
  Each `THREAD_MAP` entry carries one verdict:
187
187
  - `FIXED` — issue addressed
188
188
  - `FALSE_POSITIVE` — not a real issue; requires grep/file:line citation as evidence
189
- - `BY_DESIGN` — intentional; requires ADR or code citation as evidence
189
+ - `BY_DESIGN` — intentional; requires a recorded decision, stated in words, or code citation as evidence
190
190
  - `ESCALATED` — requires human review
191
191
 
192
192
  (The resolution gate these verdicts feed — D9 — is stated in the agent's own section.)
@@ -205,7 +205,7 @@ unexplained unresolved threads.
205
205
  - **FALSE_POSITIVE**: `After investigation, this appears to be a false positive: {evidence}. No code change needed.`
206
206
  - **BY_DESIGN**: `This is intentional: {evidence}. No code change needed.`
207
207
  - **ESCALATED**: `This thread has been escalated for human review and recorded in the resolution summary.`
208
- - Reply bodies MUST NOT contain verbatim content from the external thread body — cite only internal evidence (commit SHAs, file:line from this codebase, ADR IDs)
208
+ - Reply bodies MUST NOT contain verbatim content from the external thread body — cite only internal evidence (commit SHAs, file:line from this codebase)
209
209
  2. Write reply to `$DEVFLOW_BODY_RAW`; apply the Comment-sink scrub (D11) — non-zero exit → DEGRADED for that thread, continue per D4. Post reply via `addPullRequestReviewThreadReply` GraphQL mutation with `-F body=@"$DEVFLOW_BODY"` (file-ref form).
210
210
 
211
211
  (Step 3, the D9 gate, is stated in the agent's own section.)
@@ -76,7 +76,7 @@ One line is DELIBERATELY not here. The marker-neutralisation bullet
76
76
  NOT in its indentation — five spaces in one module and three in the other two,
77
77
  because the surrounding list nests differently. A define emits one string, so
78
78
  hoisting it would re-indent one of the three, and indentation is list grammar
79
- rather than whitespace here (PF-063). Normalising those lists is its own edit.
79
+ rather than whitespace here. Normalising those lists is its own edit.
80
80
 
81
81
  @define state_batch_line(subject, subject_ref, ref_token):
82
82
  2b. Render each issue's {{subject}} as a `**State**: {state}` line of its own, between that issue's `### Issue {{ref_token}}:` heading and its `<untrusted-issue-body>` marker — OUTSIDE the wrapper, because {{subject_ref}} is an enum the tracker computed, not remote prose. A caller refreshing a batch reads it to see a ticket closed out of band.
@@ -26,7 +26,7 @@ the single-authority corpus is the divergence this split exists to prevent.
26
26
  Headings below each section's own anchor are `###` by grammar, not by taste: a
27
27
  column-0 `## ` line outside a fence terminates the section for every guard that
28
28
  reads it through `extractOpSectionFromCorpus`, and everything under it becomes
29
- invisible while the bytes stay on disk (PF-063).
29
+ invisible while the bytes stay on disk.
30
30
 
31
31
  `_common.mds` is an ALIAS import (`as common`), as in the other two provider
32
32
  modules. A SELECTIVE import deep-copies each named function into every `@define`
@@ -226,13 +226,13 @@ This issue reached the size limit.
226
226
 
227
227
  Load when the resolved tracker provider is `github` and the operation is `create-release`.
228
228
 
229
- **Mechanics held here:** the closed-issues step only. Tag creation, release creation and notes composition stay with the operation.
229
+ **Mechanics held here:** the shipped-issues step only. Tag creation, release creation and notes composition stay with the operation.
230
230
 
231
231
  ### Process
232
232
 
233
233
  Inside step 5 (compose release notes):
234
234
 
235
- - If `SHIPPED_ISSUES` provided: append a `## Closed Issues` section with issue references — **first ≤50 issues** (the same bound `backlink-shipped-issues` applies); if truncated, add a final `…and {n} more issues` line (D4 degrade if enrichment fails)
235
+ - If `SHIPPED_ISSUES` provided: append a `## Shipped Issues` section with issue references — **first ≤50 issues** (the same bound `backlink-shipped-issues` applies); if truncated, add a final `…and {n} more issues` line (D4 degrade if enrichment fails)
236
236
  @end
237
237
 
238
238
  @define gather_release_evidence():
@@ -56,7 +56,7 @@ conflict the contract wins.
56
56
  Headings below each section's own anchor are `###` by grammar, not by taste: a
57
57
  column-0 `## ` line outside a fence terminates the section for every guard that
58
58
  reads it through `extractOpSectionFromCorpus`, and everything under it becomes
59
- invisible while the bytes stay on disk (PF-063).
59
+ invisible while the bytes stay on disk.
60
60
 
61
61
  The comment-body cap is a PROVIDER FACT and is stated once, as `comment_cap()`
62
62
  below; every site that renders it invokes the define. It is not in `_mcp.mds`
@@ -180,13 +180,13 @@ Over `{{comment_cap()}}` characters the rolling item is closed and a successor i
180
180
 
181
181
  Load when the resolved tracker provider is `jira` and the operation is `create-release`.
182
182
 
183
- **Mechanics held here:** the closed-issues step only. Tag creation, release creation and notes composition stay with the operation and are unchanged — they are release-host mechanics, not tracker mechanics.
183
+ **Mechanics held here:** the shipped-issues step only. Tag creation, release creation and notes composition stay with the operation and are unchanged — they are release-host mechanics, not tracker mechanics.
184
184
 
185
185
  ### Process
186
186
 
187
187
  Inside step 5 (compose release notes):
188
188
 
189
- - If `SHIPPED_ISSUES` is provided: append a `## Closed Issues` section rendering each entry through `## Reference Rendering` — **first ≤50 issues** (the same bound `backlink-shipped-issues` applies); if truncated, add a final `…and {n} more issues` line (D4 degrade if enrichment fails).
189
+ - If `SHIPPED_ISSUES` is provided: append a `## Shipped Issues` section rendering each entry through `## Reference Rendering` — **first ≤50 issues** (the same bound `backlink-shipped-issues` applies); if truncated, add a final `…and {n} more issues` line (D4 degrade if enrichment fails).
190
190
  - {{common.ref_preflight_list("jira", "`^[A-Z][A-Z0-9_]{1,9}-[1-9][0-9]{0,8}$`", "", "", " and the section is omitted rather than rendered empty.")}}
191
191
  - `## Reference Rendering` absent, or its token discarded by the gate below ⇒ render the key itself on its own line, and record the discard under `### Substitutions`.
192
192