devflow-kit 3.9.0 → 3.11.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 (168) hide show
  1. package/CHANGELOG.md +142 -0
  2. package/README.md +1 -1
  3. package/dist/agents/code.md +6 -6
  4. package/dist/agents/fix.md +6 -6
  5. package/dist/agents/harden.md +7 -6
  6. package/dist/agents/refactor.md +6 -6
  7. package/dist/cli/commands/ambient.js +10 -2
  8. package/dist/cli/commands/backup-session.js +131 -0
  9. package/dist/cli/commands/compliance-prompts.js +9 -4
  10. package/dist/cli/commands/compliance.js +184 -24
  11. package/dist/cli/commands/curation.js +23 -10
  12. package/dist/cli/commands/gate-level-prompts.js +39 -25
  13. package/dist/cli/commands/gates.js +5 -7
  14. package/dist/cli/commands/init.js +169 -184
  15. package/dist/cli/commands/install-report.js +129 -0
  16. package/dist/cli/commands/legacy-sweep.js +159 -0
  17. package/dist/cli/commands/proxy.js +6 -1
  18. package/dist/cli/commands/rules.js +75 -21
  19. package/dist/cli/commands/skills.js +42 -9
  20. package/dist/cli/commands/tracker.js +9 -3
  21. package/dist/cli/commands/uninstall.js +339 -75
  22. package/dist/commands/bug-analysis.md +69 -120
  23. package/dist/commands/dynamic-build.md +23 -23
  24. package/dist/commands/implement.md +46 -32
  25. package/dist/commands/release.md +1 -1
  26. package/dist/commands/resolve.md +35 -31
  27. package/dist/commands/self-review.md +8 -7
  28. package/dist/compliance-off/agents/git.md +120 -0
  29. package/dist/compliance-off/agents/triage.md +180 -0
  30. package/dist/compliance-off/commands/bug-analysis.md +398 -0
  31. package/dist/compliance-off/commands/code-review.md +520 -0
  32. package/dist/compliance-off/commands/dynamic-build.md +1251 -0
  33. package/dist/compliance-off/commands/dynamic-tickets.md +676 -0
  34. package/dist/compliance-off/commands/implement.md +736 -0
  35. package/dist/compliance-off/commands/plan.md +671 -0
  36. package/dist/compliance-off/commands/release.md +309 -0
  37. package/dist/compliance-off/commands/resolve.md +742 -0
  38. package/dist/compliance-off/skills/git/references/decision-markers.md +17 -0
  39. package/dist/compliance-off/skills/git/references/learn-conventions.md +80 -0
  40. package/dist/compliance-off/skills/git/references/pr/check-ci-status.md +33 -0
  41. package/dist/compliance-off/skills/git/references/pr/check-merge-readiness.md +49 -0
  42. package/dist/compliance-off/skills/git/references/pr/fetch-review-threads.md +52 -0
  43. package/dist/compliance-off/skills/git/references/pr/validate-branch.md +47 -0
  44. package/dist/compliance-off/skills/git/references/tracker/_contract.md +33 -0
  45. package/dist/compliance-off/skills/git/references/tracker/_mcp.md +153 -0
  46. package/dist/compliance-off/skills/git/references/tracker/github/create-release.md +35 -0
  47. package/dist/compliance-off/skills/git/references/tracker/github/ensure-pr-ready.md +100 -0
  48. package/dist/compliance-off/skills/git/references/tracker/github/ensure-traceable-issue.md +74 -0
  49. package/dist/compliance-off/skills/git/references/tracker/github/fetch-issue.md +69 -0
  50. package/dist/compliance-off/skills/git/references/tracker/github/fetch-issues-batch.md +65 -0
  51. package/dist/compliance-off/skills/git/references/tracker/github/gather-release-evidence.md +48 -0
  52. package/dist/compliance-off/skills/git/references/tracker/github/setup-task.md +77 -0
  53. package/dist/compliance-off/skills/git/references/tracker/jira/create-release.md +35 -0
  54. package/dist/compliance-off/skills/git/references/tracker/jira/ensure-pr-ready.md +100 -0
  55. package/dist/compliance-off/skills/git/references/tracker/jira/ensure-traceable-issue.md +61 -0
  56. package/dist/compliance-off/skills/git/references/tracker/jira/fetch-issue.md +51 -0
  57. package/dist/compliance-off/skills/git/references/tracker/jira/fetch-issues-batch.md +63 -0
  58. package/dist/compliance-off/skills/git/references/tracker/jira/gather-release-evidence.md +47 -0
  59. package/dist/compliance-off/skills/git/references/tracker/jira/setup-task.md +82 -0
  60. package/dist/compliance-off/skills/git/references/tracker/linear/create-release.md +35 -0
  61. package/dist/compliance-off/skills/git/references/tracker/linear/ensure-pr-ready.md +100 -0
  62. package/dist/compliance-off/skills/git/references/tracker/linear/ensure-traceable-issue.md +61 -0
  63. package/dist/compliance-off/skills/git/references/tracker/linear/fetch-issue.md +51 -0
  64. package/dist/compliance-off/skills/git/references/tracker/linear/fetch-issues-batch.md +63 -0
  65. package/dist/compliance-off/skills/git/references/tracker/linear/gather-release-evidence.md +47 -0
  66. package/dist/compliance-off/skills/git/references/tracker/linear/setup-task.md +83 -0
  67. package/dist/compliance-off/skills/git/references/trust-rule.md +7 -0
  68. package/dist/core/agent-models.js +19 -4
  69. package/dist/core/assets.js +126 -17
  70. package/dist/core/compliance-off-files.js +27 -0
  71. package/dist/core/compliance.js +14 -0
  72. package/dist/core/curation-variants.js +460 -112
  73. package/dist/core/flags.js +2 -2
  74. package/dist/core/fs-atomic.js +5 -1
  75. package/dist/core/installed-variants.js +63 -0
  76. package/dist/core/manifest.js +48 -5
  77. package/dist/core/mds-variants.js +700 -3
  78. package/dist/core/orphan-sweep.js +29 -2
  79. package/dist/core/path-set.js +15 -0
  80. package/dist/core/plugins.js +68 -10
  81. package/dist/core/reference-sweep.js +42 -25
  82. package/dist/core/retired-shipped-names.js +278 -0
  83. package/dist/curation-compliance-off/agents/triage.md +176 -0
  84. package/dist/curation-compliance-off/commands/bug-analysis.md +349 -0
  85. package/dist/curation-compliance-off/commands/code-review.md +481 -0
  86. package/dist/curation-compliance-off/commands/dynamic-build.md +1211 -0
  87. package/dist/curation-compliance-off/commands/dynamic-tickets.md +634 -0
  88. package/dist/curation-compliance-off/commands/implement.md +689 -0
  89. package/dist/curation-compliance-off/commands/plan.md +631 -0
  90. package/dist/curation-compliance-off/commands/release.md +279 -0
  91. package/dist/curation-compliance-off/commands/resolve.md +692 -0
  92. package/dist/curation-off/agents/code.md +6 -6
  93. package/dist/curation-off/agents/fix.md +6 -6
  94. package/dist/curation-off/agents/harden.md +7 -6
  95. package/dist/curation-off/agents/refactor.md +6 -6
  96. package/dist/curation-off/commands/bug-analysis.md +69 -119
  97. package/dist/curation-off/commands/dynamic-build.md +23 -23
  98. package/dist/curation-off/commands/implement.md +46 -32
  99. package/dist/curation-off/commands/release.md +1 -1
  100. package/dist/curation-off/commands/resolve.md +35 -31
  101. package/dist/curation-off/commands/self-review.md +8 -7
  102. package/dist/skills/git/references/pr/resolve-review-threads.md +1 -1
  103. package/dist/targets/claude-code/behavior-install.js +23 -9
  104. package/dist/targets/claude-code/charter-render.js +374 -0
  105. package/dist/targets/claude-code/compliance-install.js +62 -17
  106. package/dist/targets/claude-code/compliance-off-files.js +249 -0
  107. package/dist/targets/claude-code/curation-install.js +632 -117
  108. package/dist/targets/claude-code/folder-swap.js +142 -0
  109. package/dist/targets/claude-code/install-backup.js +780 -0
  110. package/dist/targets/claude-code/installer.js +795 -199
  111. package/dist/targets/claude-code/language-stamp.js +6 -0
  112. package/dist/targets/claude-code/legacy-skill-hashes.js +170 -0
  113. package/dist/targets/claude-code/linked-folder.js +176 -0
  114. package/dist/targets/claude-code/reference-converge.js +131 -0
  115. package/dist/targets/claude-code/rules-folder.js +34 -0
  116. package/dist/targets/claude-code/shipped-set.js +160 -0
  117. package/dist/targets/claude-code/tracker-install.js +21 -8
  118. package/dist/targets/claude-code/tracker-servers.js +20 -6
  119. package/dist/targets/claude-code/workflow-folder-install.js +251 -0
  120. package/dist/variant-axes.json +109 -0
  121. package/package.json +1 -1
  122. package/src/assets/agents/_partials/_code.mds +6 -6
  123. package/src/assets/agents/evaluate.md +1 -1
  124. package/src/assets/agents/git.mds +32 -0
  125. package/src/assets/agents/harden.mds +7 -6
  126. package/src/assets/agents/test.md +21 -12
  127. package/src/assets/agents/triage.mds +2 -0
  128. package/src/assets/agents/validate.md +10 -10
  129. package/src/assets/commands/_partials/_compliance.mds +5 -3
  130. package/src/assets/commands/_partials/_engine.mds +9 -8
  131. package/src/assets/commands/_partials/_publication.mds +10 -1
  132. package/src/assets/commands/bug-analysis.mds +80 -126
  133. package/src/assets/commands/code-review.mds +43 -0
  134. package/src/assets/commands/dynamic-build.mds +109 -15
  135. package/src/assets/commands/dynamic-tickets.mds +13 -0
  136. package/src/assets/commands/implement.mds +145 -33
  137. package/src/assets/commands/plan.mds +19 -0
  138. package/src/assets/commands/release.mds +50 -1
  139. package/src/assets/commands/resolve.mds +217 -32
  140. package/src/assets/commands/self-review.mds +8 -7
  141. package/src/assets/mds/git/_ops.mds +23 -0
  142. package/src/assets/mds/git/_ops_steps.mds +17 -0
  143. package/src/assets/mds/git/_pr.mds +1 -1
  144. package/src/assets/mds/git/_references.mds +6 -0
  145. package/src/assets/mds/tracker/_common.mds +4 -0
  146. package/src/assets/mds/tracker/_github.mds +42 -0
  147. package/src/assets/mds/tracker/_jira.mds +43 -0
  148. package/src/assets/mds/tracker/_linear.mds +43 -0
  149. package/src/assets/rules/quality.md +2 -0
  150. package/src/assets/scripts/ci-wait.cjs +204 -126
  151. package/src/assets/scripts/hooks/assets/implement-installed +1 -0
  152. package/src/assets/scripts/hooks/assets/orchestrator-charter.md +13 -11
  153. package/src/assets/scripts/hooks/preamble +18 -8
  154. package/src/assets/scripts/hooks/session-start-orchestrator +4 -2
  155. package/src/assets/scripts/pr-evidence.cjs +41 -2
  156. package/src/assets/scripts/verify-evidence.cjs +408 -56
  157. package/src/assets/skills/agent-references/references/commands/implement-revalidate.md +3 -3
  158. package/src/assets/skills/agent-references/references/commands/plan-levels.md +1 -1
  159. package/src/assets/skills/agent-references/references/synthesize/bug-analysis.md +6 -2
  160. package/src/assets/skills/agent-references/references/validate/passed-alone.md +7 -7
  161. package/src/assets/skills/docs-framework/SKILL.md +5 -2
  162. package/src/assets/skills/git/SKILL.md +3 -3
  163. package/src/assets/skills/git/references/github-api.md +2 -139
  164. package/src/assets/skills/git/references/github-posting.md +158 -0
  165. package/src/assets/skills/review-methodology/SKILL.md +1 -1
  166. package/src/assets/skills/review-methodology/references/patterns.md +1 -1
  167. package/src/assets/skills/review-methodology/references/report-template.md +1 -2
  168. package/src/assets/skills/testing/SKILL.md +2 -4
@@ -43,7 +43,7 @@ This command instructs you to construct and run a Claude Code dynamic Workflow t
43
43
  Before authoring, verify:
44
44
 
45
45
  1. **Workflow tool available:** if the `Workflow` tool is not in your available tools, STOP and tell the user: "The Workflow tool is not available in this session. dynamic-build requires Claude Code's dynamic workflow runtime."
46
- 2. **`agentType` support:** confirmed available (spike F5, 2026-06-11). If spawned agents return no results, check that devflow is installed (`devflow init` has been run).
46
+ 2. **`agentType` support:** if spawned agents return no results, check that devflow is installed (`devflow init` has been run).
47
47
  3. **Tracker paths:** an issue reference or URL in the input is read through the Git agent, which resolves the configured tracker and its access itself and reports `TRACEABILITY: DEGRADED ({reason})` when it cannot read one — then note it and fall back to the issue text the user provided. No tracker CLI is checked here.
48
48
  4. **No-remote path:** if the repo has no remote, skip the remote-dependent steps (the wave PR and its evidence) and proceed with local branch operations only; the Git agent reports DEGRADED for any tracker step it cannot reach.
49
49
 
@@ -58,6 +58,9 @@ Before you write the workflow script:
58
58
  **Produces:** EVIDENCE_POLICY, ISSUE_REQUIRED, APPLY_CONVENTIONS, REQUIRE_NON_AUTHOR_APPROVAL
59
59
 
60
60
  {{evidence_policy()}}
61
+ <!-- compliance:off -->
62
+ When `EVIDENCE_POLICY` is `required`, record `TRACEABILITY: DEGRADED (compliance off on this machine; the repository requires evidence)` once, for the run summary.
63
+ <!-- compliance:end -->
61
64
 
62
65
  Author the resolved `ISSUE_REQUIRED` and `APPLY_CONVENTIONS` into the workflow script as constants — pass them as `issueRequired` and `applyConventions` when invoking the workflow — and pass both to the Git `setup-task` spawn.
63
66
 
@@ -135,7 +138,11 @@ Check, in priority order:
135
138
 
136
139
  If a number is found, record it as the command-level `ISSUE_NUMBER`:
137
140
  - **SINGLE mode:** it is the ticket's own reference. Pass it as `issueNumber: <number>` when invoking the workflow; the engine hands it to setup-task as `ISSUE_INPUT`. If none is found, pass nothing.
141
+ <!-- compliance:on -->
138
142
  - **WAVE mode:** it is the tracking issue. Only steps 2 and 3 after the workflow use it: step 2 for the wave report, step 3 for the wave block's tracking line. It never reaches a ticket: each ticket's engine gets that ticket's own reference as `issueInput`.
143
+ <!-- compliance:off -->
144
+ - **WAVE mode:** it is the tracking issue. Only step 3 after the workflow uses it, for the wave block's tracking line. It never reaches a ticket: each ticket's engine gets that ticket's own reference as `issueInput`.
145
+ <!-- compliance:end -->
139
146
 
140
147
  Never pass `ISSUE_PR_LINK` into the workflow. The engine binds each ticket's `ISSUE_NUMBER` and `ISSUE_PR_LINK` from that ticket's own setup-task Output (`### Handoff Values`), never from the token it passed in, and returns that ticket's `issuePrLink` for the wave PR's related line. No `- **PR link line**:` captured ⇒ `ISSUE_PR_LINK` is `"(none)"` and the ticket's related line carries no closing reference.
141
148
 
@@ -227,7 +234,7 @@ After implementing, commit your changes with a conventional-commit message and r
227
234
  );
228
235
 
229
236
  // Phase 3: Gate 1 #1 — post-code pipeline: Polish agent → Harden agent → Validate agent.
230
- // Validate runs last and unconditionally, so its one full run covers every commit the pass made (see gate1_postcode()).
237
+ // Validate runs last and unconditionally, so its one full run covers every commit the pass made.
231
238
  const gate1 = await phase("gate1", async () => {
232
239
  await agent(`Polish and reduce complexity of recent changes on branch ${BRANCH}. Commit any improvements.`, { agentType: "Polish" });
233
240
 
@@ -288,8 +295,7 @@ Criteria: ${CRITERIA || "see plan"}
288
295
  Return: {"verdict": "PASS" | "FAIL", "rationale": "..."} — FAIL if either answer is no, naming the failing criterion or the drift.`, { agentType: "Evaluate" });
289
296
  evalVerdict = evaluation?.verdict === "PASS" ? "PASS" : "FAIL";
290
297
  if (evalVerdict === "FAIL") {
291
- // fix-and-continue — no re-evaluate, no inline Gate 1. The final Gate 1 (#2)
292
- // after the review pass is the build gate before the branch is handed back.
298
+ // fix-and-continue — no re-evaluate, no inline Gate 1.
293
299
  await agent(`OPERATION: alignment-fix
294
300
  Fix the alignment issues identified by the Evaluate agent on branch ${BRANCH}:
295
301
  ${evaluation?.rationale || "see the Evaluate agent's report"}
@@ -308,19 +314,21 @@ Self-verify your fix compiles, following your Running commands block. Commit fix
308
314
  ${CRITERIA || "(none)"}
309
315
  TEST_PLAN: ${TEST_PLAN || "(none)"}
310
316
  Follow your Running commands block for every scenario command.
311
- Cover: functionality, API contracts, performance, and cover every TEST_PLAN scenario. Report: PASS or FAIL per scenario.`, { agentType: "Test" });
312
- testVerdict = testResult.verdict;
317
+ Cover: functionality, API contracts, performance, and cover every TEST_PLAN scenario.
318
+ Return: {"verdict": "PASS" | "FAIL" | "BLOCKED", "failures": "..."}`, { agentType: "Test" });
319
+ const word = testResult?.verdict?.split?.(/[ (]/)[0];
320
+ testVerdict = ["PASS", "FAIL"].includes(word) ? word : "BLOCKED";
313
321
  if (testVerdict === "FAIL") {
314
322
  // fix-and-continue — no re-test, no inline Gate 1.
315
323
  await agent(`OPERATION: qa-fix
316
324
  Fix the failing acceptance test scenarios on branch ${BRANCH}:
317
- ${testResult.failures}
325
+ ${testResult.failures || "see the Test agent's report"}
318
326
  <!-- curation:on -->
319
327
  DECISIONS_CONTEXT: ${DECISIONS_CONTEXT}
320
328
  <!-- curation:end -->
321
329
  ${COMPLIANCE_DIRECTIVE}
322
330
  Self-verify your fix compiles and the scenarios pass, following your Running commands block. Commit fixes.`, { agentType: "Fix" });
323
- testVerdict = "FAIL-FIXED"; // issues found, fixes applied, not re-evaluated by design
331
+ testVerdict = "FAIL-FIXED";
324
332
  }
325
333
  }
326
334
 
@@ -468,8 +476,6 @@ Return: {"status": "fixed"|"blocked", "commitShas": ["<sha>"], "unresolved": ["<
468
476
  });
469
477
 
470
478
  // Phase 5.5: Gate 1 #2 — FINAL post-fix gate (Polish agent → Harden agent → full Validate agent, Validate last and unconditional).
471
- // Runs ONCE, after the review pass. Inside the pass the Code agent self-verified its own fixes;
472
- // this is the build gate before the branch is handed back. See gate1_postcode() cadence.
473
479
  const gate1Final = await phase("gate1-final", async () => {
474
480
  await agent(`Polish and reduce complexity of recent changes on branch ${BRANCH}. Commit any improvements.`, { agentType: "Polish" });
475
481
 
@@ -506,9 +512,9 @@ Return: {"verdict": "PASS" | "FAIL", "details": "..."}`, { agentType: "Validate"
506
512
  });
507
513
 
508
514
  // PASS requires survivingFindings.length === 0 && coverageGaps.length === 0 && gate1Final.verdict !== "ESCALATED"
509
- // and no FAIL-FIXED Gate 2 verdict: fixes applied but never re-run report UNVERIFIED, never PASS
515
+ // and every Gate 2 verdict PASS or SKIPPED; any other reports UNVERIFIED, never PASS
510
516
  const coverageGaps = reviewResult.coverageGaps || [];
511
- const gate2Unverified = [gate2.evaluateVerdict, gate2.testVerdict].includes("FAIL-FIXED");
517
+ const gate2Unverified = ![gate2.evaluateVerdict, gate2.testVerdict].every(v => v === "PASS" || v === "SKIPPED");
512
518
  const overallVerdict = (reviewResult.survivingFindings?.length || 0) === 0 && coverageGaps.length === 0 && gate1Final.verdict !== "ESCALATED" ? (gate2Unverified ? "UNVERIFIED" : "PASS") : "PARTIAL";
513
519
 
514
520
  // Phase 6: Report — the phase returns the engine result (engine_output_schema); its verdict is overallVerdict
@@ -681,6 +687,7 @@ return { tickets: WAVE_TICKETS.map(t => results[t] || { ticket: t, ran: false, v
681
687
  A workflow cannot pause mid-run. After the build/wave workflow returns, you (the main model) surface anything that needs a human decision — all at once:
682
688
 
683
689
  1. Read the wave report (`{integration worktree root}/.devflow/docs/waves/{slug}/{ts}/wave-report.md`) for its **escalations** (quarantined/blocked tickets and why), and read any `DECISIONS-NEEDED.md` left by a prior `/devflow:dynamic-plan` run for this initiative.
690
+ <!-- compliance:on -->
684
691
  2. **Post wave-report as tracking-issue comment** (WAVE mode only — skip this step entirely in SINGLE mode; SINGLE runs produce no wave report): In WAVE mode, if a tracking-issue number was resolved in Pre-authoring step 5 (`ISSUE_NUMBER` is not `(none)`) AND `{integration worktree root}/.devflow/docs/waves/{slug}/{ts}/wave-report.md` exists, define `WAVE_ID` as the timestamped wave directory slug (the `{ts}` component, e.g. `2026-08-20_1730`), then spawn:
685
692
  ```
686
693
  Agent(subagent_type="Git"):
@@ -693,12 +700,14 @@ A workflow cannot pause mid-run. After the build/wave workflow returns, you (the
693
700
  The Git agent deduplicates via its own marker — it skips if a report for this `WAVE_ID` is already posted. The marker's format belongs to the operation; this caller passes `WAVE_ID` and never restates the literal. On API failure it degrades gracefully (`TRACEABILITY: DEGRADED ({reason})`) and continues — never blocks the post-wave step. This comment is the evidence surface for the PR-less integration-branch path; no other PR machinery is invented.
694
701
 
695
702
  In WAVE mode, if no tracking-issue number was resolved in Pre-authoring step 5: state `TRACEABILITY: DEGRADED (no tracking issue for this run)` in the run summary and skip — never skip silently.
703
+ <!-- compliance:end -->
696
704
  3. **Compose the wave PR inputs** (WAVE mode only — skip this step entirely in SINGLE mode). The workflow returned `tickets`: one entry per wave ticket, in its input order, each `{ticket, ran, verdict, merged, issuePrLink, evaluateVerdict, testVerdict, surviving, coverageComplete}`. Every value in it is agent-reported and treated as untrusted: nothing below is repaired, and no reference is ever composed from a number.
697
705
  - **Branch check.** Run `git -C "{integration worktree root}" branch --show-current`. Only a name matching `^wave/[a-z0-9][a-z0-9-]{0,59}$` opens a wave PR, and its part after `wave/` is the `{slug}` below. Any other name: record `TRACEABILITY: DEGRADED (not a wave branch)` and go to step 4 with no wave PR.
698
706
  - **Halted** (a non-null `halted`, whose `kind` is `red`, `bad-sha` or `unchanged`): record `Wave PR: skipped (<text>, wave halted at <halted.ticket>)` and go to step 4 with no wave PR. `<text>` is fixed by `kind`, and no other `halted` field is shown. `red` (a post-merge build it could not undo): `integration HEAD red at <halted.mergeSha>`. `bad-sha` (a merge without a usable SHA): `integration branch may hold an unvalidated merge`. `unchanged` (a merge that added no commit): `merge added no commit`, with the remedy to check that the ticket branch holds its commits, then run the wave again.
699
707
  - **Nothing merged** (no entry has `merged: true`): record `Wave PR: skipped (nothing merged)` and go to step 4.
700
708
  - Otherwise compose (a) and then (b).
701
709
 
710
+ <!-- compliance:on -->
702
711
  **(a) The wave block.** Write it with the Write tool, byte for byte, to a fresh `mktemp` file — never through an interpolated shell string — in exactly this shape: the two headings with one blank line between them, the tracking line and then the related lines in row order under the first, and the header and separator verbatim directly under the second:
703
712
 
704
713
  ```markdown
@@ -726,9 +735,35 @@ node "$HOME/.devflow/scripts/verify-evidence.cjs" check wave <that file>; echo "
726
735
  ```
727
736
 
728
737
  Only `exit=0` admits the file's text, verbatim, as `PR_WAVE_BLOCK`. Any other result: no wave PR — record `Wave PR: not opened (wave block refused: <the code on stderr>)` and go to step 4.
738
+ <!-- compliance:off -->
739
+ **(a) The wave block.** Number the `tickets` entries `T1` … `Tn` in order. Write the block with the Write tool, byte for byte, to a fresh `mktemp` file — never through an interpolated shell string — in exactly this shape: the heading, then the tracking line and the related lines in entry order under it. It has no verdict table and no evidence section:
729
740
 
741
+ ```markdown
742
+ ## Related Issues
743
+ Refs {tracking ref}
744
+ {one related line per entry that has one}
745
+ ```
746
+
747
+ **Related line.** An entry's captured `issuePrLink` is the only source of a reference. When it is not `(none)` and the reference it names (its text after `Closes ` or `Refs `) is, as a whole, a `#N` or `KEY-N` reference, the related line is `Refs ` and that reference. Any other entry has no related line. No line is `Closes`: the block holds no verdict, so it closes no issue.
748
+
749
+ **Tracking line** — only when Pre-authoring step 5 resolved a tracking issue whose token is, as a whole, a `#N` or `KEY-N` reference: `Refs ` and that token, verbatim, as the first line under `## Related Issues`. Any other token (a bare number, a URL), or none ⇒ no tracking line: nothing is composed from a number.
750
+
751
+ With no line under the heading, `PR_WAVE_BLOCK` is `(none)` and nothing is checked. Otherwise check the file:
752
+
753
+ ```bash
754
+ node "$HOME/.devflow/scripts/verify-evidence.cjs" check wave --links-only <that file>; echo "exit=$?"
755
+ ```
756
+
757
+ Only `exit=0` admits the file's text, verbatim, as `PR_WAVE_BLOCK`. Any other result: no wave PR — record `Wave PR: not opened (wave block refused: <the code on stderr>)` and go to step 4.
758
+ <!-- compliance:end -->
759
+
760
+ <!-- compliance:on -->
730
761
  **Required link** — only when `EVIDENCE_POLICY` is `required`: a `PASS` or `UNVERIFIED` row whose Ticket is `(none)` — a merged ticket whose setup-task captured an Issue ID but no link line, so the wave PR would close nothing for it — ⇒ `Wave PR: BLOCKED (no ticket link for T<k>, …)`, with no wave PR question and the remedy "link or create those tickets' issues, then re-run"; there is no exception. Under `standard` such a row stays as the Ticket rule above renders it.
762
+ <!-- compliance:off -->
763
+ **Required link** — only when `EVIDENCE_POLICY` is `required`: a merged entry (`merged: true` with `verdict` `PASS` or `UNVERIFIED`) whose `issuePrLink` is `(none)` — a merged ticket whose setup-task captured an Issue ID but no link line — ⇒ `Wave PR: BLOCKED (no ticket link for T<k>, …)`, with no wave PR question and the remedy "link or create those tickets' issues, then re-run"; there is no exception. Under `standard` such an entry only has no related line.
764
+ <!-- compliance:end -->
731
765
 
766
+ <!-- compliance:on -->
732
767
  **(b) The wave test plan.** Take the checked TP lines each merged row's ticket was given in Pre-authoring step 4, in row order; renumber them `TP-1`, `TP-2`, … and prefix each scenario with its row's `T<k>: `. A line is never shortened or reworded: one whose prefixed scenario would pass 200 characters leaves its ticket with no usable test plan. Write `## Test Plan` and those lines, and nothing else, to `"{integration worktree root}/.devflow/docs/evidence-wave-{slug}.md"` with the Write tool, then run (the path double-quoted; one rewrite from the same lines after a refusal, never a second):
733
768
 
734
769
  ```bash
@@ -737,10 +772,27 @@ node "$HOME/.devflow/scripts/verify-evidence.cjs" render --plan "{integration wo
737
772
  ```
738
773
 
739
774
  Only when both exit 0 is `PR_TEST_PLAN_BLOCK` the render's stdout, byte for byte without its `exit=` line; in every other case it is `(none)`.
775
+ <!-- compliance:off -->
776
+ **(b) The wave test plan.** Take the checked TP lines each merged entry's ticket was given in Pre-authoring step 4, in entry order; renumber them `TP-1`, `TP-2`, … and prefix each scenario with its entry's `T<k>: `. A line is never shortened or reworded: one whose prefixed scenario would pass 200 characters leaves its ticket with no usable test plan. Write `## Test Plan` and those lines, and nothing else, to `"{integration worktree root}/.devflow/docs/evidence-wave-{slug}.md"` with the Write tool, then run (the path double-quoted; one rewrite from the same lines after a refusal, never a second):
740
777
 
778
+ ```bash
779
+ node "$HOME/.devflow/scripts/verify-evidence.cjs" check tp "{integration worktree root}/.devflow/docs/evidence-wave-{slug}.md"; echo "exit=$?"
780
+ ```
781
+
782
+ Only `exit=0` leaves a usable wave test plan; in every other case none remains.
783
+ <!-- compliance:end -->
784
+
785
+ <!-- compliance:on -->
741
786
  **Required plan** — only when `EVIDENCE_POLICY` is `required`: a merged ticket with no usable test plan ⇒ `Wave PR: BLOCKED (no test plan for T<k>, …)`, more than 200 lines in all ⇒ `Wave PR: BLOCKED (test plan over 200 lines)`, and a plan that did not check and render ⇒ `Wave PR: BLOCKED (test plan malformed)` — each with no wave PR question and the remedy "run `/devflow:dynamic-plan` for those tickets and re-run, or ship them through `/implement`"; no exception is offered here. Otherwise the block is optional: a ticket with no usable test plan is left out of it and named in the summary, and `(none)` is passed when no line remains.
787
+ <!-- compliance:off -->
788
+ **Required plan** — only when `EVIDENCE_POLICY` is `required`: a merged ticket with no usable test plan ⇒ `Wave PR: BLOCKED (no test plan for T<k>, …)`, more than 200 lines in all ⇒ `Wave PR: BLOCKED (test plan over 200 lines)`, and a plan that did not check ⇒ `Wave PR: BLOCKED (test plan malformed)` — each with no wave PR question and the remedy "run `/devflow:dynamic-plan` for those tickets and re-run, or ship them through `/implement`"; no exception is offered here. Otherwise the plan is optional: a ticket with no usable test plan is left out of it and named in the summary, and step 7 skips its evidence when no line remains.
789
+ <!-- compliance:end -->
742
790
  4. Surface ALL of them — escalations AND open decisions — to the user in ONE batched `AskUserQuestion` (never one-at-a-time). `_wave.mds`'s escalation model already quarantines-and-continues; this batches the surfacing so the user answers everything in a single pass.
791
+ <!-- compliance:on -->
743
792
  - **The wave PR question.** Only when step 3 composed `PR_WAVE_BLOCK`, the batch gains exactly one question: "Open the wave PR from wave/{slug}? It links {n} merged tickets ({u} UNVERIFIED) and references {q} quarantined." It has exactly two options: open it, or don't. The counts come from the checked block's rows: `{n}` PASS and UNVERIFIED, `{u}` UNVERIFIED, `{q}` QUARANTINED.
793
+ <!-- compliance:off -->
794
+ - **The wave PR question.** Only when step 3 set `PR_WAVE_BLOCK`, to its admitted text or to `(none)`, the batch gains exactly one question: "Open the wave PR from wave/{slug}? It references {n} linked tickets." It has exactly two options: open it, or don't. `{n}` is the number of related lines in the checked block, the tracking line aside, and 0 when `PR_WAVE_BLOCK` is `(none)`.
795
+ <!-- compliance:end -->
744
796
  - A `ticket-link-missing` escalation carries its remedy: link or create that ticket's issue, then re-run. There is no per-ticket exception.
745
797
  - **Headless** — `AskUserQuestion` is unavailable, or no answer comes — is a decline: nothing is created and nothing is pushed.
746
798
  5. If `~/.devflow/preference-profile.md` was absent, note in your summary: "no preference profile found — N decisions surfaced that a profile might have auto-resolved; consider `/devflow:dynamic-profile`."
@@ -749,18 +801,38 @@ node "$HOME/.devflow/scripts/verify-evidence.cjs" render --plan "{integration wo
749
801
  Agent(subagent_type="Git"):
750
802
  "OPERATION: ensure-pr-ready
751
803
  WORKTREE_PATH: {integration worktree root}
804
+ <!-- compliance:on -->
752
805
  PR_DESCRIPTION_GUIDANCE: {counts only — the wave slug and the merged, quarantined and blocked counts; never an issue title or body}
806
+ <!-- compliance:off -->
807
+ PR_DESCRIPTION_GUIDANCE: {counts only — the wave slug and the count of linked issues; never an issue title or body}
808
+ <!-- compliance:end -->
753
809
  APPLY_CONVENTIONS: {APPLY_CONVENTIONS}
810
+ <!-- compliance:on -->
754
811
  PR_WAVE_BLOCK: {PR_WAVE_BLOCK verbatim}
755
812
  PR_TEST_PLAN_BLOCK: {PR_TEST_PLAN_BLOCK verbatim, or (none)}"
813
+ <!-- compliance:off -->
814
+ PR_WAVE_BLOCK: {PR_WAVE_BLOCK verbatim, or (none)}"
815
+ <!-- compliance:end -->
756
816
  ```
817
+ <!-- compliance:on -->
757
818
  The Git agent pastes each block only behind its own check. Report its `**PR**` line and any `TRACEABILITY: DEGRADED ({reason})` lines. The wave PR is opened here and nowhere else; it is never merged, and main is never touched — the user merges.
819
+ <!-- compliance:off -->
820
+ The Git agent pastes the block only behind its own check. Report its `**PR**` line and any `TRACEABILITY: DEGRADED ({reason})` lines. The wave PR is opened here and nowhere else; it is never merged, and main is never touched — the user merges.
821
+ <!-- compliance:end -->
758
822
 
759
823
  Do NOT ask questions mid-workflow — that is impossible (F4). The workflow only WRITES the report; you read it and ask.
760
824
 
825
+ <!-- compliance:on -->
761
826
  7. **Wave PR evidence** — only when step 6 reported the wave PR, after it; it never blocks, and every outcome below goes into the run summary. Take `{n}` from step 6's `- **PR**: #{n}` line when `{n}` matches `^[1-9][0-9]{0,9}$` as a whole; no such line ⇒ record `TRACEABILITY: DEGRADED (wave PR number not captured)` and skip this step. `PR_TEST_PLAN_BLOCK` `(none)` ⇒ record `Wave evidence: skipped (no wave test plan)` and skip it.
827
+ <!-- compliance:off -->
828
+ 7. **Wave PR evidence** — only when step 6 reported the wave PR, after it; it never blocks, and every outcome below goes into the run summary. Take `{n}` from step 6's `- **PR**: #{n}` line when `{n}` matches `^[1-9][0-9]{0,9}$` as a whole; no such line ⇒ record `TRACEABILITY: DEGRADED (wave PR number not captured)` and skip this step. No wave test plan line ⇒ record `Wave evidence: skipped (no wave test plan)` and skip (a)-(d).
829
+ <!-- compliance:end -->
762
830
 
831
+ <!-- compliance:on -->
763
832
  **Changed files.** Take `{base_ref}` from step 6's `- **Base ref**:` line; only when it is 40 or 64 lowercase hex, run `git -C "{integration worktree root}" diff --name-only --diff-filter=d {base_ref}...HEAD; echo "exit=$?"`. Unless it ran and printed `exit=0`, record `TRACEABILITY: DEGRADED (wave base unusable)` and skip this step.
833
+ <!-- compliance:off -->
834
+ **Changed files.** Take `{base_ref}` from step 6's `- **Base ref**:` line; only when it is 40 or 64 lowercase hex, run `git -C "{integration worktree root}" diff --name-only --diff-filter=d {base_ref}...HEAD; echo "exit=$?"`. Unless it ran and printed `exit=0`, record `TRACEABILITY: DEGRADED (wave base unusable)` and skip (a)-(d).
835
+ <!-- compliance:end -->
764
836
 
765
837
  **(a) Test the wave.** Spawn one Test agent on the integration worktree with the wave test plan — the TP lines of the `## Test Plan` section step 3(b) wrote to `{integration worktree root}/.devflow/docs/evidence-wave-{slug}.md`:
766
838
 
@@ -770,12 +842,12 @@ Agent(subagent_type="Test"):
770
842
  FILES_CHANGED: {the file list that diff printed}
771
843
  TEST_PLAN: {the TP lines of the wave evidence file's ## Test Plan section}
772
844
  WORKTREE_PATH: {integration worktree root}
773
- Cover every TEST_PLAN line on the integration branch as it stands. Report PASS or FAIL with evidence."
845
+ Cover every TEST_PLAN line on the integration branch as it stands. Report your Status with evidence."
774
846
  ```
775
847
 
776
- Nothing is fixed here, PASS or FAIL: the wave is done and its PR is open. Report the Test agent's Status.
848
+ Nothing is fixed here, whatever the Status: the wave is done and its PR is open. Report the Test agent's Status.
777
849
 
778
- **(b) Claims.** Append its TP claims, PASS or FAIL alike, to the `## Claims` section of `"{integration worktree root}/.devflow/docs/evidence-wave-{slug}.md"` — the file's last section, created when absent. Append only: never edit or remove a claim. Each line is `/implement`'s TP claim, keyed to the 40-hex `HEAD:` the Test agent's report shows:
850
+ **(b) Claims.** Append its TP claims, whatever its Status, to the `## Claims` section of `"{integration worktree root}/.devflow/docs/evidence-wave-{slug}.md"` — the file's last section, created when absent. Append only: never edit or remove a claim. Each line is `/implement`'s TP claim, keyed to the 40-hex `HEAD:` the Test agent's report shows:
779
851
 
780
852
  ```
781
853
  - TP-<n> <PASS|FAIL|SKIP> sha:<head> by:test exit:<0-255>
@@ -789,8 +861,13 @@ Cover every TEST_PLAN line on the integration branch as it stands. Report PASS o
789
861
  git -C "{integration worktree root}" push origin HEAD; echo "exit=$?"
790
862
  ```
791
863
 
864
+ <!-- compliance:on -->
792
865
  Any result but `exit=0`, a rejected non-fast-forward push included ⇒ record `TRACEABILITY: DEGRADED (evidence push failed)` and refresh anyway.
866
+ <!-- compliance:off -->
867
+ Any result but `exit=0`, a rejected non-fast-forward push included ⇒ record `TRACEABILITY: DEGRADED (evidence push failed)` and verify anyway.
868
+ <!-- compliance:end -->
793
869
 
870
+ <!-- compliance:on -->
794
871
  **(d) Refresh.** Resolve the publication value for the integration worktree:
795
872
 
796
873
  {{pub.publication_gate()}}
@@ -802,6 +879,23 @@ cd "{integration worktree root}" && node "$HOME/.devflow/scripts/verify-evidence
802
879
  ```
803
880
 
804
881
  `{n}` is the number admitted above, and the publication value is `auto`, `full`, `off` or `stub`. `publish` decides what each publication value means for the evidence comment. Report its `## PR Evidence` block — its `EVIDENCE` line and its `**Body**:` / `**Comment**:` line — with any `TRACEABILITY: DEGRADED ({reason})` lines after it, or its `TRACEABILITY: DEGRADED (evidence unavailable)` line; empty stdout or any other exit ⇒ `TRACEABILITY: DEGRADED (evidence refresh failed)`. Whatever it returns, the run ends here.
882
+ <!-- compliance:off -->
883
+ **(d) Verify locally.** Run the script inline, with no Git agent spawn. It reads the PR and the wave evidence file and writes the local result file; it writes nothing to GitHub:
884
+
885
+ ```bash
886
+ cd "{integration worktree root}" && node "$HOME/.devflow/scripts/verify-evidence.cjs" verify --pr {n} --evidence ".devflow/docs/evidence-wave-{slug}.md" --comment-out ".devflow/docs/evidence-result-wave-{slug}.md"; echo "exit=$?"
887
+ ```
888
+
889
+ `{n}` is the number admitted above. Report its one `EVIDENCE` line, then `Evidence result: .devflow/docs/evidence-result-wave-{slug}.md (local; not posted)`. Empty stdout or any other exit ⇒ `TRACEABILITY: DEGRADED (evidence unavailable)`. It never blocks.
890
+
891
+ **(e) Readiness.** Run the local merge check, once, the same way:
892
+
893
+ ```bash
894
+ cd "{integration worktree root}" && node "$HOME/.devflow/scripts/verify-evidence.cjs" readiness --pr {n} --require-non-author-approval {REQUIRE_NON_AUTHOR_APPROVAL} --evidence ".devflow/docs/evidence-wave-{slug}.md" --out ".devflow/docs/readiness-wave-{slug}.md"; echo "exit=$?"
895
+ ```
896
+
897
+ Pass `--require-non-author-approval` the value of `REQUIRE_NON_AUTHOR_APPROVAL`, `true` or `false`. Drop the `--evidence` pair when (a)-(d) were skipped. Its stdout is the `## Merge Readiness` block (exit 0), or the same block with `**Status**: DEGRADED ({reason})` and a `TRACEABILITY: DEGRADED ({reason})` line after it (exit 2). Report its verdict (READY, NOT_READY or DEGRADED) and its `- Test plan:` detail line, then `Readiness: .devflow/docs/readiness-wave-{slug}.md (local; not posted)`. Empty stdout or any other exit ⇒ `TRACEABILITY: DEGRADED (readiness unavailable)`. Whatever it returns, the run ends here.
898
+ <!-- compliance:end -->
805
899
 
806
900
  ---
807
901
 
@@ -56,6 +56,9 @@ Before you write the workflow script:
56
56
  **Produces:** EVIDENCE_POLICY, ISSUE_REQUIRED, APPLY_CONVENTIONS, REQUIRE_NON_AUTHOR_APPROVAL
57
57
 
58
58
  {{evidence_policy()}}
59
+ <!-- compliance:off -->
60
+ When `EVIDENCE_POLICY` is `required`, record `TRACEABILITY: DEGRADED (compliance off on this machine; the repository requires evidence)` once, for the filing report.
61
+ <!-- compliance:end -->
59
62
 
60
63
  {{docs_root()}}
61
64
 
@@ -223,7 +226,9 @@ Agent(subagent_type="Git"):
223
226
  "OPERATION: ensure-traceable-issue
224
227
  TASK_DESCRIPTION: {the ticket's title, or the tracking issue's H1}
225
228
  REQUIREMENTS: {the ticket's **Wave:** and **Depends on:** lines, then its ## Summary paragraph; or the tracking issue's ## Context}
229
+ <!-- compliance:on -->
226
230
  PLAN_ARTIFACT_PATH: {the ticket or tracking-issue file path, relative to {worktree}}
231
+ <!-- compliance:end -->
227
232
  WORKTREE_PATH: {worktree}"
228
233
  ```
229
234
 
@@ -231,9 +236,17 @@ WORKTREE_PATH: {worktree}"
231
236
  - `CREATED` or `ENRICHED`, with a reference that matches `^(#[1-9][0-9]{0,8}|[A-Z][A-Z0-9_]{0,9}-[1-9][0-9]{0,8})$` as a whole ⇒ insert `**Issue:** {ISSUE_REF}` with the Edit tool: in a ticket file as the line directly after its `**Depends on:**` line, in `tracking-issue.md` as the line directly after its H1. Change nothing else in the file.
232
237
  - A reference of any other shape ⇒ `TRACEABILITY: DEGRADED (issue reference "{ref}" does not match any tracker reference grammar)`, and no line.
233
238
  - `DEGRADED (rate limited)` ⇒ stop filing: this file and every file after it are reported `not filed`. Any other DEGRADED ⇒ that file gets no line; report it and go on to the next.
239
+ <!-- compliance:on -->
234
240
  4. **Report** each file's `**Issue:**` reference, or `not filed` and why, with every `TRACEABILITY: DEGRADED` line step 2 and the spawns produced.
241
+ <!-- compliance:off -->
242
+ 4. **Report** each file's `**Issue:**` reference, or `not filed` and why, with the compliance-off line of Pre-authoring step 0 and every `TRACEABILITY: DEGRADED` line step 2 and the spawns produced.
243
+ <!-- compliance:end -->
235
244
 
245
+ <!-- compliance:on -->
236
246
  `/devflow:dynamic-build` reads these lines: the tracking issue's for its wave report, and each ticket's as that ticket's own reference.
247
+ <!-- compliance:off -->
248
+ `/devflow:dynamic-build` reads these lines: the tracking issue's for its wave block's tracking line, and each ticket's as that ticket's own reference.
249
+ <!-- compliance:end -->
237
250
 
238
251
  ---
239
252