devflow-kit 3.7.0 → 3.9.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 (205) hide show
  1. package/CHANGELOG.md +479 -1
  2. package/README.md +15 -15
  3. package/dist/agents/code.md +6 -8
  4. package/dist/agents/design.md +1 -1
  5. package/dist/agents/fix.md +7 -8
  6. package/dist/agents/git.md +3 -3
  7. package/dist/agents/harden.md +1 -1
  8. package/dist/agents/refactor.md +2 -4
  9. package/dist/agents/review.md +4 -4
  10. package/dist/agents/skim.md +2 -2
  11. package/dist/agents/triage.md +9 -2
  12. package/dist/cli/commands/capture.js +1 -1
  13. package/dist/cli/commands/curation-move-io.js +102 -0
  14. package/dist/cli/commands/curation-move-step.js +374 -0
  15. package/dist/cli/commands/curation.js +808 -0
  16. package/dist/cli/commands/gate-level-prompts.js +428 -0
  17. package/dist/cli/commands/gates.js +35 -11
  18. package/dist/cli/commands/init-seed.js +11 -8
  19. package/dist/cli/commands/init.js +244 -57
  20. package/dist/cli/commands/memory.js +60 -13
  21. package/dist/cli/commands/prompt-io.js +37 -0
  22. package/dist/cli/commands/uninstall.js +157 -17
  23. package/dist/cli.js +2 -2
  24. package/dist/commands/bug-analysis.md +25 -36
  25. package/dist/commands/code-review.md +40 -44
  26. package/dist/commands/debug.md +5 -5
  27. package/dist/commands/dynamic-build.md +26 -25
  28. package/dist/commands/dynamic-plan.md +5 -5
  29. package/dist/commands/dynamic-profile.md +5 -5
  30. package/dist/commands/dynamic-tickets.md +5 -5
  31. package/dist/commands/explore.md +6 -6
  32. package/dist/commands/implement.md +53 -82
  33. package/dist/commands/plan.md +6 -6
  34. package/dist/commands/release.md +5 -5
  35. package/dist/commands/research.md +6 -6
  36. package/dist/commands/resolve.md +39 -41
  37. package/dist/commands/self-review.md +5 -13
  38. package/dist/core/area-pause-notice.js +44 -0
  39. package/dist/core/assets.js +20 -20
  40. package/dist/core/curate-tuning-config.js +5 -6
  41. package/dist/core/curation-move-notice.js +84 -0
  42. package/dist/core/curation-move-skip.js +35 -0
  43. package/dist/core/curation-move.js +35 -0
  44. package/dist/core/curation-queue-cleanup.js +135 -0
  45. package/dist/core/curation-store.js +99 -0
  46. package/dist/core/{learning-variants.js → curation-variants.js} +65 -41
  47. package/dist/core/echo-value.js +11 -5
  48. package/dist/core/evidence-policy.js +11 -9
  49. package/dist/core/feature-switch.js +95 -19
  50. package/dist/core/fs-atomic.js +1 -1
  51. package/dist/core/gate-level.js +10 -2
  52. package/dist/core/git.js +16 -14
  53. package/dist/core/ledger-root.js +82 -22
  54. package/dist/core/linked-path.js +4 -4
  55. package/dist/core/manifest-lock.js +238 -0
  56. package/dist/core/manifest.js +58 -14
  57. package/dist/core/migrations.js +1 -13
  58. package/dist/core/observations.js +2 -2
  59. package/dist/core/plugins.js +19 -19
  60. package/dist/core/pool.js +26 -0
  61. package/dist/core/project-paths.js +103 -34
  62. package/dist/core/queue-drain.js +2 -2
  63. package/dist/core/tracked-areas.js +159 -0
  64. package/dist/core/tracker.js +1 -1
  65. package/dist/{learning-off → curation-off}/agents/code.md +6 -8
  66. package/dist/{learning-off → curation-off}/agents/fix.md +7 -8
  67. package/dist/{learning-off → curation-off}/agents/refactor.md +2 -4
  68. package/dist/{learning-off → curation-off}/agents/review.md +3 -3
  69. package/dist/{learning-off → curation-off}/agents/triage.md +8 -1
  70. package/dist/{learning-off → curation-off}/commands/bug-analysis.md +20 -31
  71. package/dist/{learning-off → curation-off}/commands/code-review.md +37 -41
  72. package/dist/{learning-off → curation-off}/commands/debug.md +2 -2
  73. package/dist/{learning-off → curation-off}/commands/dynamic-build.md +23 -22
  74. package/dist/{learning-off → curation-off}/commands/explore.md +2 -2
  75. package/dist/{learning-off → curation-off}/commands/implement.md +50 -79
  76. package/dist/{learning-off → curation-off}/commands/plan.md +2 -2
  77. package/dist/{learning-off → curation-off}/commands/resolve.md +36 -38
  78. package/dist/{learning-off → curation-off}/commands/self-review.md +2 -10
  79. package/dist/hud/components/{learning-counts.js → curation-counts.js} +63 -17
  80. package/dist/hud/config.js +1 -1
  81. package/dist/hud/index.js +6 -6
  82. package/dist/hud/render.js +3 -3
  83. package/dist/skills/git/references/pr/post-resolution-summary.md +12 -11
  84. package/dist/skills/git/references/pr/post-review-summary.md +12 -11
  85. package/dist/skills/git/references/pr/update-pr-evidence.md +2 -2
  86. package/dist/skills/git/references/pr/validate-branch.md +8 -5
  87. package/dist/skills/git/references/publication-gate.md +6 -7
  88. package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +13 -5
  89. package/dist/skills/git/references/tracker/github/manage-debt.md +6 -2
  90. package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +13 -5
  91. package/dist/skills/git/references/tracker/jira/manage-debt.md +6 -2
  92. package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +13 -5
  93. package/dist/skills/git/references/tracker/linear/manage-debt.md +6 -2
  94. package/dist/targets/claude-code/{learning-install.js → curation-install.js} +85 -65
  95. package/dist/targets/claude-code/installer.js +15 -15
  96. package/dist/targets/claude-code/language-stamp.js +5 -5
  97. package/dist/targets/claude-code/post-install.js +2 -2
  98. package/dist/targets/claude-code/tracker-servers.js +1 -1
  99. package/package.json +3 -2
  100. package/src/assets/agents/_partials/_code.mds +11 -11
  101. package/src/assets/agents/code.mds +6 -6
  102. package/src/assets/agents/curate.md +8 -8
  103. package/src/assets/agents/debug.mds +6 -6
  104. package/src/assets/agents/design.mds +18 -18
  105. package/src/assets/agents/evaluate.md +6 -12
  106. package/src/assets/agents/fix.mds +7 -6
  107. package/src/assets/agents/git.mds +3 -3
  108. package/src/assets/agents/harden.mds +7 -7
  109. package/src/assets/agents/knowledge.mds +23 -23
  110. package/src/assets/agents/refactor.mds +2 -2
  111. package/src/assets/agents/research.mds +15 -15
  112. package/src/assets/agents/review.mds +43 -43
  113. package/src/assets/agents/skim.mds +11 -11
  114. package/src/assets/agents/triage.mds +29 -22
  115. package/src/assets/agents/validate.md +30 -50
  116. package/src/assets/commands/_partials/_decisions.mds +22 -20
  117. package/src/assets/commands/_partials/_engine.mds +8 -8
  118. package/src/assets/commands/_partials/_knowledge.mds +29 -15
  119. package/src/assets/commands/_partials/_preamble.mds +4 -4
  120. package/src/assets/commands/_partials/_settings.mds +3 -3
  121. package/src/assets/commands/_partials/_wave.mds +7 -7
  122. package/src/assets/commands/bug-analysis.mds +37 -48
  123. package/src/assets/commands/code-review.mds +53 -57
  124. package/src/assets/commands/debug.mds +14 -14
  125. package/src/assets/commands/dynamic-build.mds +38 -37
  126. package/src/assets/commands/dynamic-plan.mds +22 -22
  127. package/src/assets/commands/dynamic-profile.mds +2 -2
  128. package/src/assets/commands/dynamic-tickets.mds +8 -8
  129. package/src/assets/commands/explore.mds +20 -20
  130. package/src/assets/commands/implement.mds +77 -98
  131. package/src/assets/commands/plan.mds +27 -27
  132. package/src/assets/commands/release.mds +12 -12
  133. package/src/assets/commands/research.mds +19 -19
  134. package/src/assets/commands/resolve.mds +66 -60
  135. package/src/assets/commands/self-review.mds +20 -20
  136. package/src/assets/mds/git/_ops.mds +9 -2
  137. package/src/assets/mds/git/_ops_pr.mds +21 -11
  138. package/src/assets/mds/git/_ops_steps.mds +20 -4
  139. package/src/assets/mds/git/_pr.mds +21 -18
  140. package/src/assets/mds/git/_references.mds +6 -7
  141. package/src/assets/mds/tracker/_github.mds +1 -4
  142. package/src/assets/mds/tracker/_jira.mds +1 -4
  143. package/src/assets/mds/tracker/_linear.mds +1 -4
  144. package/src/assets/rules/quality.md +1 -0
  145. package/src/assets/scripts/ci-wait.cjs +389 -92
  146. package/src/assets/scripts/hooks/background-memory-update +81 -3
  147. package/src/assets/scripts/hooks/capture-prompt +12 -12
  148. package/src/assets/scripts/hooks/capture-question +11 -11
  149. package/src/assets/scripts/hooks/capture-turn +12 -12
  150. package/src/assets/scripts/hooks/{learning-lock → curation-lock} +2 -2
  151. package/src/assets/scripts/hooks/curation-move +293 -0
  152. package/src/assets/scripts/hooks/ensure-devflow-init +45 -13
  153. package/src/assets/scripts/hooks/ensure-proxy +4 -4
  154. package/src/assets/scripts/hooks/ensure-root-gitignore +4 -4
  155. package/src/assets/scripts/hooks/git-marker +81 -0
  156. package/src/assets/scripts/hooks/json-helper.cjs +176 -51
  157. package/src/assets/scripts/hooks/json-parse +1 -1
  158. package/src/assets/scripts/hooks/lib/curation-move.cjs +1582 -0
  159. package/src/assets/scripts/hooks/lib/{learning-store.cjs → curation-store.cjs} +308 -122
  160. package/src/assets/scripts/hooks/lib/decisions-format.cjs +3 -3
  161. package/src/assets/scripts/hooks/lib/mkdir-lock.cjs +24 -7
  162. package/src/assets/scripts/hooks/lib/project-paths.cjs +132 -39
  163. package/src/assets/scripts/hooks/lib/render-decisions.cjs +42 -22
  164. package/src/assets/scripts/hooks/lib/tracked-areas.cjs +452 -0
  165. package/src/assets/scripts/hooks/memory-permission +10 -2
  166. package/src/assets/scripts/hooks/memory-worker +12 -1
  167. package/src/assets/scripts/hooks/pre-compact-memory +17 -16
  168. package/src/assets/scripts/hooks/queue-append +444 -102
  169. package/src/assets/scripts/hooks/resolve-project-root +2 -2
  170. package/src/assets/scripts/hooks/session-start-context +198 -72
  171. package/src/assets/scripts/hooks/session-start-memory +42 -43
  172. package/src/assets/scripts/lib/project-config.cjs +12 -5
  173. package/src/assets/scripts/pr-evidence.cjs +5 -2
  174. package/src/assets/scripts/resolve-base.cjs +1043 -0
  175. package/src/assets/scripts/resolve-settings.cjs +283 -45
  176. package/src/assets/scripts/verify-evidence.cjs +307 -75
  177. package/src/assets/skills/agent-references/SKILL.md +11 -2
  178. package/src/assets/skills/agent-references/references/commands/implement-levels.md +29 -0
  179. package/src/assets/skills/agent-references/references/commands/implement-revalidate.md +6 -4
  180. package/src/assets/skills/agent-references/references/commands/resolve-levels.md +25 -0
  181. package/src/assets/skills/agent-references/references/synthesize/review.md +4 -4
  182. package/src/assets/skills/agent-references/references/triage/severity-tiers.md +43 -0
  183. package/src/assets/skills/agent-references/references/validate/passed-alone.md +14 -0
  184. package/src/assets/skills/apply-decisions/SKILL.md +1 -1
  185. package/src/assets/skills/docs-framework/SKILL.md +7 -7
  186. package/src/assets/skills/docs-framework/references/patterns.md +3 -4
  187. package/src/assets/skills/quality-gates/SKILL.md +1 -1
  188. package/src/assets/skills/worktree-support/references/roots.md +2 -2
  189. package/templates/lint-pack/.lint-pack.conf +86 -0
  190. package/templates/lint-pack/README.md +190 -0
  191. package/templates/lint-pack/lint-pack.sh +905 -0
  192. package/dist/cli/commands/learning.js +0 -554
  193. package/dist/core/learning-queue-cleanup.js +0 -27
  194. package/dist/core/learning-store.js +0 -61
  195. /package/dist/{learning-off → curation-off}/agents/debug.md +0 -0
  196. /package/dist/{learning-off → curation-off}/agents/design.md +0 -0
  197. /package/dist/{learning-off → curation-off}/agents/harden.md +0 -0
  198. /package/dist/{learning-off → curation-off}/agents/knowledge.md +0 -0
  199. /package/dist/{learning-off → curation-off}/agents/research.md +0 -0
  200. /package/dist/{learning-off → curation-off}/agents/skim.md +0 -0
  201. /package/dist/{learning-off → curation-off}/commands/dynamic-plan.md +0 -0
  202. /package/dist/{learning-off → curation-off}/commands/dynamic-profile.md +0 -0
  203. /package/dist/{learning-off → curation-off}/commands/dynamic-tickets.md +0 -0
  204. /package/dist/{learning-off → curation-off}/commands/release.md +0 -0
  205. /package/dist/{learning-off → curation-off}/commands/research.md +0 -0
@@ -10,7 +10,7 @@ output-dir: dist/commands
10
10
  @import "./_partials/_settings.mds" as settings
11
11
  # Code Review Command
12
12
 
13
- Run a comprehensive code review of the current branch by spawning parallel review agents, then synthesizing results into PR comments. Supports incremental reviews, timestamped report directories, and multi-worktree auto-discovery.
13
+ Run a comprehensive code review of the current branch by spawning parallel review agents, then synthesizing results into PR comments.
14
14
 
15
15
  ## Usage
16
16
 
@@ -34,8 +34,8 @@ Run a comprehensive code review of the current branch by spawning parallel revie
34
34
  - **More than one listed:** Invoke the `devflow:worktree-support` skill, then Read its `references/discovery.md` from the skill's base directory for the full 7-step algorithm; the canonical protected branch list stays in the skill. Parse the list, filter (skip protected/detached/mid-rebase), dedup by branch, sort by recent commit
35
35
  - **Exactly one listed:** load neither the skill nor the reference — that worktree is the only candidate, and Step 0c's Git agent validates its branch
36
36
  2. **If `--path` flag provided:** use only that worktree, skip discovery
37
- **`--path` validation**: Before proceeding, verify the path exists as a directory and appears in `git worktree list` output. If not: report error and stop.
38
- 3. **If only 1 reviewable worktree**: proceed as single-worktree flow — zero behavior change
37
+ **`--path` validation**: the path must be a directory in `git worktree list` output; if not, report an error and stop.
38
+ 3. **If only 1 reviewable worktree**: proceed as single-worktree flow
39
39
  4. **If multiple reviewable worktrees:** report "Found N worktrees with reviewable branches: {list with paths and branches}" and proceed with multi-worktree flow
40
40
 
41
41
  #### Step 0b: Resolve the compliance lens and gate level
@@ -84,20 +84,20 @@ PR_DESCRIPTION_GUIDANCE: {pr_description_guidance}
84
84
  PR_TEST_PLAN_BLOCK: {PR_TEST_PLAN_BLOCK verbatim, or (none)}
85
85
  APPLY_CONVENTIONS: {APPLY_CONVENTIONS}
86
86
  Validate branch, commit if needed, push, create PR if needed.
87
- Return: branch, base_branch, branch-slug, PR#"
87
+ Return: branch, base_branch, base_ref, branch-slug, PR#"
88
88
  ```
89
89
 
90
90
  In multi-worktree mode, spawn all pre-flight agents **in a single message**.
91
91
 
92
92
  **If BLOCKED:** In single-worktree mode, stop and report. In multi-worktree mode, report the failure but continue with other worktrees.
93
93
 
94
- **Extract from response:** `branch`, `base_branch`, `branch_slug`, `pr_number` per worktree.
94
+ **Extract from response:** `branch`, `base_branch`, `base_ref`, `branch_slug`, `pr_number` per worktree. Stop with cause and fix when the Base line reads (rejected) or `branch_slug` does not match the slug pattern above; name the Git agent's fix, never your own, and for the slug the allowed characters, never its value. In multi-worktree mode this blocks only that worktree.
95
95
 
96
96
  **Fetch PR body** (after extracting `pr_number`):
97
97
  ```bash
98
98
  PR_DESCRIPTION=$(gh pr view {pr_number} --json body --jq '.body' 2>/dev/null || echo "(none)")
99
99
  ```
100
- If `pr_number` is absent or the command fails, set `PR_DESCRIPTION` to `(none)`.
100
+ If `pr_number` is absent, set `PR_DESCRIPTION` to `(none)`.
101
101
 
102
102
  #### Step 0d: Incremental Detection & Timestamp Setup
103
103
 
@@ -107,26 +107,27 @@ If `pr_number` is absent or the command fails, set `PR_DESCRIPTION` to `(none)`.
107
107
  For each worktree:
108
108
 
109
109
  1. Generate timestamp: `YYYY-MM-DD_HHMM`. If directory already exists (same-minute collision), append seconds (`YYYY-MM-DD_HHMMSS`).
110
- 2. Create timestamped review directory: `mkdir -p {worktree}/.devflow/docs/reviews/{branch-slug}/{timestamp}/`
111
- 3. Check if `{worktree}/.devflow/docs/reviews/{branch-slug}/.last-review-head` exists:
110
+ 2. Check if `{gd}/devflow/reviews/{branch-slug}/.last-review-head` exists, `{gd}` being what `git -C "{worktree}" rev-parse --absolute-git-dir` prints:
112
111
  - **If yes AND `--full` NOT set:**
113
- - Read the SHA from the file
114
- - Verify reachable: `git -C {worktree} cat-file -t {sha}` (handles rebases — if unreachable, fallback to full)
112
+ - The stored review head is checked as a commit ID: use it only when it is exactly 40 or 64 lowercase hex, else take the full-range path
113
+ - Verify reachable: `git -C "{worktree}" cat-file -t {sha}` must print `commit` (else take the full-range path)
115
114
  - Check if SHA == current HEAD → if so, skip review: "No new commits since last review. Use --full for a full re-review."
116
115
  - Set `DIFF_RANGE` to `{last-review-sha}...HEAD`
117
- - **If no (first review), or `--full`:**
118
- - Set `DIFF_RANGE` to `{base_branch}...HEAD`
116
+ - **Full-range path (no marker, or `--full`):**
117
+ - Stop as for a (rejected) Base line unless `base_ref` is 40 or 64 hex.
118
+ - Set `DIFF_RANGE` to `{base_ref}...HEAD`
119
+ 3. Create timestamped review directory: `mkdir -p {worktree}/.devflow/docs/reviews/{branch-slug}/{timestamp}/`
119
120
 
120
121
  #### Step 0e-i: Load Prior Resolution and Count Cycles
121
122
 
122
123
  **Produces:** PRIOR_RESOLUTIONS, CYCLE_NUMBER
123
124
  **Requires:** BRANCH_INFO
124
125
 
125
- For each worktree, perform a single pass over timestamped directories:
126
- 1. List timestamped directories in `{worktree}/.devflow/docs/reviews/{branch-slug}/` sorted descending: `ls -1d {worktree}/.devflow/docs/reviews/{branch-slug}/20* 2>/dev/null | sort -r`
127
- 2. Iterate once: accumulate CYCLE_NUMBER count for each directory containing `resolution-summary.md`; capture the first (most-recent) such directory as PRIOR_DIR.
126
+ For each worktree:
127
+ 1. List the timestamped directories: `ls -1d {worktree}/.devflow/docs/reviews/{branch-slug}/20* 2>/dev/null | sort -r`
128
+ 2. Iterate once: count each directory containing `resolution-summary.md` as CYCLE_NUMBER; capture the first (newest) as PRIOR_DIR.
128
129
  3. If CYCLE_NUMBER = 0: set PRIOR_RESOLUTIONS=(none), CYCLE_NUMBER=1, proceed.
129
- 4. Otherwise: set CYCLE_NUMBER = count + 1. Read `{PRIOR_DIR}/resolution-summary.md` as PRIOR_RESOLUTIONS.
130
+ 4. Otherwise: set CYCLE_NUMBER = count + 1. Read `{PRIOR_DIR}/resolution-summary.md` as PRIOR_RESOLUTIONS minus each section from a heading line (fenced or not) with the word `Private` (any case) not followed by a letter or digit, to the next unfenced heading with as many `#` as its start or fewer, else at end of file. Close any fence it leaves open. When unsure, cut more; if the cut fails, PRIOR_RESOLUTIONS=(none).
130
131
  5. If `--full`: still load PRIOR_RESOLUTIONS.
131
132
 
132
133
  #### Step 0e-ii: Convergence Assessment
@@ -144,7 +145,7 @@ MAX_REVIEW_CYCLES = 10
144
145
  - `deferred_count` = the Deferred row value (= FIX_SEPARATE + TECH_DEBT); By Design and Escalated are excluded from the fp_ratio denominator
145
146
  - fp_ratio = fp_count / (fp_count + fixed_count + deferred_count)
146
147
  - If denominator = 0: fp_ratio = 0, skip warning
147
- - If parsing fails: fp_ratio = 0, skip warning; note in output: "Warning: Could not parse Statistics table from prior resolution. FP ratio unavailable — convergence tracking degraded."
148
+ - If parsing fails: fp_ratio = 0, skip warning; note in output: "Warning: Could not parse Statistics table. Convergence tracking degraded."
148
149
  3. If fp_ratio > 0.7 AND CYCLE_NUMBER >= 3:
149
150
  Warn in output: "⚠️ Convergence: {ratio}% false positives in cycle {N-1}. Consider merging or manual inspection."
150
151
  Continue with review.
@@ -182,10 +183,11 @@ List the changed paths into `{REVIEW_DIR}/paths.txt` and print only the line cou
182
183
 
183
184
  ```bash
184
185
  git -C "{WORKTREE_PATH}" diff --name-only --no-renames {DIFF_RANGE} > "{REVIEW_DIR}/paths.txt"
186
+ echo "exit=$?"
185
187
  wc -l < "{REVIEW_DIR}/paths.txt"
186
188
  ```
187
189
 
188
- Read `paths.txt` once when the count is about 40 or fewer, and in ranges of about 40 lines (Read with offset and limit) when it is more.
190
+ The `exit=` line is the diff's. A non-zero diff exit stops. Read `paths.txt` once when the count is about 40 or fewer, and in ranges of about 40 lines (Read with offset and limit) when it is more.
189
191
 
190
192
  Set `DIFF_CLASS` by these rules, in order; the first that decides wins:
191
193
 
@@ -259,7 +261,7 @@ Write `diff.patch` once per worktree, by redirect:
259
261
  git -C "{WORKTREE_PATH}" diff --no-color --no-ext-diff --no-textconv {DIFF_RANGE} > "{REVIEW_DIR}/diff.patch"
260
262
  ```
261
263
 
262
- It holds the whole diff of `DIFF_RANGE`. On a `code` diff, add one patch for each language focus in REVIEW_FOCUS_LIST, by the same command with quoted pathspecs from this table:
264
+ It holds the whole diff of `DIFF_RANGE`. A non-zero exit of any patch write stops. On a `code` diff, add one patch for each language focus in REVIEW_FOCUS_LIST, by the same command with quoted pathspecs from this table:
263
265
 
264
266
  ```bash
265
267
  git -C "{WORKTREE_PATH}" diff --no-color --no-ext-diff --no-textconv {DIFF_RANGE} -- '<pathspec>' ... > "{REVIEW_DIR}/diff-{focus}.patch"
@@ -277,39 +279,39 @@ git -C "{WORKTREE_PATH}" diff --no-color --no-ext-diff --no-textconv {DIFF_RANGE
277
279
 
278
280
  The core, database, dependencies, documentation and compliance focuses, and every reduced-class focus, read `diff.patch`. A language focus sees only its own extensions and reaches anything else through `DIFF_RANGE`. Set `DIFF_FILES` to the files written. They live in `REVIEW_DIR`, under the gitignored `.devflow/` tree, with `paths.txt`: never committed, posted or passed to the Git agent.
279
281
 
280
- <!-- learning:on -->
282
+ <!-- curation:on -->
281
283
  ### Phase 1b: Load Decisions Index
282
- <!-- learning:off -->
284
+ <!-- curation:off -->
283
285
  ### Phase 1b: Load Context
284
- <!-- learning:end -->
286
+ <!-- curation:end -->
285
287
 
286
- <!-- learning:on -->
288
+ <!-- curation:on -->
287
289
  **Produces:** DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, FEATURE_KNOWLEDGE_RULES, COMPLIANCE_FRAMEWORKS (carried from Step 0b)
288
- <!-- learning:off -->
290
+ <!-- curation:off -->
289
291
  **Produces:** FEATURE_KNOWLEDGE, FEATURE_KNOWLEDGE_RULES, COMPLIANCE_FRAMEWORKS (carried from Step 0b)
290
- <!-- learning:end -->
292
+ <!-- curation:end -->
291
293
 
292
294
  {{decisions_load()}}
293
- <!-- learning:on -->
295
+ <!-- curation:on -->
294
296
  This produces a compact index of active ADR/PF entries. Pass `DECISIONS_CONTEXT` to all Review agents as one shared slice, cut over the diff's files. Review agents use `devflow:apply-decisions` to Read full entry bodies on demand.
295
297
 
296
- <!-- learning:end -->
298
+ <!-- curation:end -->
297
299
  {{knowledge_load()}}
298
300
 
299
- <!-- learning:on -->
301
+ <!-- curation:on -->
300
302
  Pass `FEATURE_KNOWLEDGE` to all Review agents alongside `DECISIONS_CONTEXT`.
301
- <!-- learning:off -->
303
+ <!-- curation:off -->
302
304
  Pass `FEATURE_KNOWLEDGE` to all Review agents.
303
- <!-- learning:end -->
305
+ <!-- curation:end -->
304
306
 
305
307
  ### Phase 2: Run Reviews (Parallel)
306
308
 
307
309
  **Produces:** REVIEW_FOCUS_OUTPUTS
308
- <!-- learning:on -->
310
+ <!-- curation:on -->
309
311
  **Requires:** DIFF_RANGE, REVIEW_DIR, TIMESTAMP, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, PR_DESCRIPTION, PRIOR_RESOLUTIONS, REVIEW_FOCUS_LIST, DIFF_CLASS, DIFF_FILES
310
- <!-- learning:off -->
312
+ <!-- curation:off -->
311
313
  **Requires:** DIFF_RANGE, REVIEW_DIR, TIMESTAMP, FEATURE_KNOWLEDGE, PR_DESCRIPTION, PRIOR_RESOLUTIONS, REVIEW_FOCUS_LIST, DIFF_CLASS, DIFF_FILES
312
- <!-- learning:end -->
314
+ <!-- curation:end -->
313
315
 
314
316
  Spawn Review agents **in a single message**, one per focus in REVIEW_FOCUS_LIST (max 20 per worktree):
315
317
 
@@ -339,7 +341,7 @@ Spawn Review agents **in a single message**, one per focus in REVIEW_FOCUS_LIST
339
341
  | documentation | conditional | devflow:documentation | diff.patch |
340
342
  | compliance | diff-driven | devflow:compliance | diff.patch |
341
343
 
342
- Review agent count: at `full`, `code` runs 8 core +1-12; `standard` runs up to 2 fewer; lean `code` runs 3-4; a reduced class or a mix runs 2-6.
344
+ Review agent count: `code` runs 8 core +1-12 at `full`, up to 2 fewer at `standard`, 3-4 at lean; a reduced class or a mix runs 2-6.
343
345
 
344
346
  {{compliance_focus_inject()}}
345
347
 
@@ -352,22 +354,22 @@ PR: #{pr_number}, Base: {base_branch}
352
354
  WORKTREE_PATH: {worktree_path} (omit if cwd)
353
355
  DIFF_FILE: {diff_file} (absolute: {REVIEW_DIR}/diff.patch, or {REVIEW_DIR}/diff-{focus}.patch for a language focus, per the table)
354
356
  DIFF_RANGE: {DIFF_RANGE} (information only)
355
- <!-- learning:on -->
357
+ <!-- curation:on -->
356
358
  DECISIONS_CONTEXT: {decisions_context}
357
- <!-- learning:end -->
359
+ <!-- curation:end -->
358
360
  FEATURE_KNOWLEDGE: {feature_knowledge}
359
361
  PR_DESCRIPTION: <pr-description>{pr_description}</pr-description>
360
362
  PRIOR_RESOLUTIONS: <prior-resolution-summary>{prior_resolutions}</prior-resolution-summary>
361
363
  {COMPLIANCE_FOCUS_DIRECTIVE} (compliance focus only)
362
364
  If PRIOR_RESOLUTIONS is not (none), follow Cross-Cycle Awareness in review.md.
363
- <!-- learning:on -->
365
+ <!-- curation:on -->
364
366
  Follow devflow:apply-decisions to scan the index and Read full ADR/PF bodies on demand.
365
- <!-- learning:end -->
367
+ <!-- curation:end -->
366
368
  Follow devflow:apply-feature-knowledge for FEATURE_KNOWLEDGE — feature-specific patterns and anti-patterns inform findings.
367
369
  IMPORTANT: Write report to {worktree_path}/.devflow/docs/reviews/{branch-slug}/{timestamp}/{focus}.md using Write tool"
368
370
  ```
369
371
 
370
- In multi-worktree mode, process worktrees **sequentially**: complete Phases 1-4 for one worktree before starting the next, so Review spawns never pile up.
372
+ In multi-worktree mode, process worktrees **sequentially**: Phases 1-4 for each.
371
373
 
372
374
  ### Phase 3: Synthesis → Review Comment (Sequential)
373
375
 
@@ -402,7 +404,7 @@ CYCLE_NUMBER: {cycle_number}
402
404
  REVIEW_TIMESTAMP: {timestamp}
403
405
  REVIEW_PUBLICATION: {REVIEW_PUBLICATION}
404
406
  WORKTREE_PATH: {worktree_path} (omit if cwd)
405
- Posts the consolidated review-summary comment (marker-deduped by the operation on the cycle+timestamp pair)."
407
+ Posts the consolidated review-summary comment (marker-deduped on the cycle+timestamp pair)."
406
408
  ```
407
409
 
408
410
  ### Phase 4: Write Review Head Marker & Report
@@ -410,34 +412,29 @@ Posts the consolidated review-summary comment (marker-deduped by the operation o
410
412
  **Requires:** BRANCH_INFO, REVIEW_DIR
411
413
 
412
414
  Per worktree, after successful completion:
413
- 1. Write current HEAD SHA to `{worktree_path}/.devflow/docs/reviews/{branch-slug}/.last-review-head`
415
+ 1. In one Bash call run `M="$(git -C "{worktree_path}" rev-parse --absolute-git-dir)/devflow/reviews/{branch-slug}" && mkdir -p "$M" && git -C "{worktree_path}" rev-parse HEAD > "$M/.last-review-head"`. A failed or refused write never stops the run and is not retried another way.
414
416
  2. Display results from all agents:
415
417
  - Merge recommendation (from Synthesize agent)
416
418
  - Issue counts by category (🔴 blocking / ⚠️ should-fix / ℹ️ pre-existing)
417
419
  - Review comment status: POSTED / POSTED+TRUNCATED (body exceeded 60k after redaction) / SKIPPED (D7 dedup) / DEGRADED (from Git)
418
420
  - Publication status: FULL (private repo) | FULL (config override) | STUB (public repository) | OFF (publication disabled by config) | STUB (visibility undeterminable) | STUB (evidence policy) (from Git agent)
421
+ - Any base `TRACEABILITY: DEGRADED` line from Step 0c, as returned
419
422
  - Artifact paths
420
423
 
421
424
  ## Architecture
422
425
 
423
426
  ```
424
- /code-review (orchestrator - spawns agents only)
427
+ /code-review
425
428
  │
426
- ├─ Phase 0: Worktree Discovery & Pre-flight
427
- │ ├─ Step 0a: git worktree list → filter reviewable
429
+ ├─ Phase 0: Worktree Discovery & Pre-flight, Steps 0a-0f (Git agent per worktree, parallel)
428
430
  │ ├─ Step 0b: Resolve the compliance lens and gate level
429
- │ ├─ Step 0c: Git agent (ensure-pr-ready) per worktree [parallel]
430
- │ ├─ Step 0d: Incremental detection + timestamp setup per worktree
431
- │ ├─ Step 0e-i: Load prior resolution-summary.md
432
- │ ├─ Step 0e-ii: Convergence assessment (warn only)
433
- │ └─ Step 0f: Resolve REVIEW_PUBLICATION per worktree (publication gate)
434
431
  │
435
- ├─ Per worktree (SEQUENTIAL — one worktree at a time):
432
+ ├─ Per worktree (SEQUENTIAL):
436
433
  │ │
437
434
  │ ├─ Phase 1: Analyze changed files
438
435
  │ │ ├─ Classify the diff (paths.txt → DIFF_CLASS)
439
- │ │ ├─ Choose the focuses (code: file types + the language stamp; all: the gate level)
440
- │ │ └─ Write diff.patch and diff-{focus}.patch, by redirect
436
+ │ │ ├─ Choose the focuses
437
+ │ │ └─ Write diff.patch and diff-{focus}.patch
441
438
  │ │
442
439
  │ ├─ Phase 2: Reviews (PARALLEL within worktree), one per REVIEW_FOCUS_LIST focus
443
440
  │ │ ├─ code: core (diff.patch), language (diff-{focus}.patch), conditional
@@ -455,7 +452,7 @@ Per worktree, after successful completion:
455
452
  | Case | Handling |
456
453
  |------|----------|
457
454
  | `--full` in multi-worktree mode | Applies to all worktrees (global modifier). It sets the diff range, never the gate level |
458
- | Review comment already posted | Git agent matches its own marker on the `{cycle, timestamp}` pair → skip silently (D7); a re-review in the same cycle (different timestamp) posts its own comment. The marker's format belongs to the operation; this caller passes the pair and never restates the literal |
455
+ | Review comment already posted | Git agent matches its own marker on the `{cycle, timestamp}` pair → skip silently (D7) |
459
456
  | Docs-only diff | Its Step 1.1 set, narrowed by level |
460
457
  | Tests-only diff | Its Step 1.1 set, narrowed by level |
461
458
  | Lockfile-only diff | Its Step 1.1 set, narrowed by level |
@@ -464,8 +461,7 @@ Per worktree, after successful completion:
464
461
  | A file moved across classes | `--no-renames` lists both paths, so a code path makes the diff `code` |
465
462
  | Path listing above about 40 lines | Read in ranges (Step 1.1) |
466
463
  | Language files changed, plugin not installed | The focus is absent from the stamped line: not spawned |
467
- | Public repo (`auto` mode) | Git agent probes visibility, posts counts-only STUB comment; full report stays local |
468
- | `reviewPublication: off` | Git agent skips posting the review comment (OFF) — except that, only when `EVIDENCE_POLICY` is `required`, Step 0f passes `stub` and a counts-only STUB comment posts |
464
+ | `reviewPublication: off` | Git agent skips posting the review comment (OFF) — except that, only when `EVIDENCE_POLICY` is `required`, Step 0f passes `stub` and a counts-only STUB comment posts unless no public text remains |
469
465
 
470
466
  ## Backwards Compatibility
471
467
 
@@ -473,8 +469,8 @@ Per worktree, after successful completion:
473
469
 
474
470
  ## Principles
475
471
 
476
- 1. **Orchestration only** - Command spawns agents, doesn't do git/review work itself. The exceptions are the read-only Phase 0 probes (`git worktree list`, `git -C ... branch --show-current`, `git -C ... cat-file -t`), the bounded Phase 1 path listing (a redirect into `paths.txt`, a `wc -l` count and ranged reads) and the redirect-only patch writes (`diff.patch`, `diff-{focus}.patch`). Redirect-only writes print nothing, so no diff content reaches this thread
472
+ 1. **Orchestration only** - Command spawns agents, doesn't do git/review work itself. The exceptions are the read-only Phase 0 probes (`git worktree list`, `git -C ... branch --show-current`, `git -C ... cat-file -t`, `git -C ... rev-parse`), the bounded Phase 1 path listing and the writes (`diff.patch`, `diff-{focus}.patch`, the marker and its `mkdir -p`). These writes print nothing
477
473
  2. **Parallel, not background** - Multiple agents in one message, but `run_in_background=false` so phases complete before proceeding
478
- 3. **Git agent for git work** - All git operations go through Git agent, except the exceptions named in Principle 1; redirect-only writes print nothing
474
+ 3. **Git agent for git work** - All git operations go through Git agent, except the exceptions named in Principle 1; its writes print nothing
479
475
  4. **Honest reporting** - Display agent outputs directly
480
476
  5. **Incremental by default** - Only review new changes unless `--full` specified
@@ -34,16 +34,16 @@ $ARGUMENTS
34
34
 
35
35
  ## Phases
36
36
 
37
- <!-- learning:on -->
37
+ <!-- curation:on -->
38
38
  ### Phase 1: Load Decisions Index (Orchestrator-Local)
39
- <!-- learning:off -->
39
+ <!-- curation:off -->
40
40
  ### Phase 1: Resolve Settings
41
- <!-- learning:end -->
41
+ <!-- curation:end -->
42
42
 
43
- <!-- learning:on -->
43
+ <!-- curation:on -->
44
44
  **Produces:** DECISIONS_CONTEXT
45
45
 
46
- <!-- learning:end -->
46
+ <!-- curation:end -->
47
47
  {{settings.settings_resolve()}}
48
48
 
49
49
  From the same line: {{compliance.compliance_frameworks()}}
@@ -53,18 +53,18 @@ From the same line: {{compliance.compliance_frameworks()}}
53
53
  Phase 7 passes `COMPLIANCE_DIRECTIVE` to the Code agent that implements the fix, on a line of its own.
54
54
 
55
55
  {{decisions_load()}}
56
- <!-- learning:on -->
56
+ <!-- curation:on -->
57
57
  The orchestrator uses `DECISIONS_CONTEXT` locally when generating hypotheses (Phase 2) — prior pitfalls and decisions can suggest specific root causes to investigate. Follow `devflow:apply-decisions` to Read full entry bodies on demand. **Do NOT pass `DECISIONS_CONTEXT` to Explore investigators** — decisions context stays in the orchestrator; investigators examine code directly.
58
58
 
59
- <!-- learning:end -->
59
+ <!-- curation:end -->
60
60
  **No up-front feature knowledge load** — debug investigation workers read code directly to avoid confirmation bias. Feature knowledge is only written back at the end if the investigation surfaced durable, cross-cutting knowledge.
61
61
 
62
62
  ### Phase 2: Context Gathering
63
63
 
64
64
  **Produces:** HYPOTHESES, BUG_CONTEXT
65
- <!-- learning:on -->
65
+ <!-- curation:on -->
66
66
  **Requires:** DECISIONS_CONTEXT
67
- <!-- learning:end -->
67
+ <!-- curation:end -->
68
68
 
69
69
  If `COMMAND_INPUT` opens with a candidate issue reference, fetch the issue:
70
70
 
@@ -211,9 +211,9 @@ Ask user via AskUserQuestion: "Want me to implement this fix?"
211
211
  TASK_DESCRIPTION: Implement the fix for this root cause: {bug description}
212
212
  EXECUTION_PLAN: {Root Cause, Key Findings and Recommended Fix from Phase 6, with their file:line references}
213
213
  PUSH: false
214
- <!-- learning:on -->
214
+ <!-- curation:on -->
215
215
  DECISIONS_CONTEXT: {decisions_context}
216
- <!-- learning:end -->
216
+ <!-- curation:end -->
217
217
  FEATURE_KNOWLEDGE: (none)
218
218
  {COMPLIANCE_DIRECTIVE}"
219
219
  ```
@@ -227,11 +227,11 @@ Ask user via AskUserQuestion: "Want me to implement this fix?"
227
227
  ```
228
228
  /debug (orchestrator)
229
229
  │
230
- <!-- learning:on -->
230
+ <!-- curation:on -->
231
231
  ├─ Phase 1: Load Decisions Index (Orchestrator-Local)
232
- <!-- learning:off -->
232
+ <!-- curation:off -->
233
233
  ├─ Phase 1: Resolve Settings
234
- <!-- learning:end -->
234
+ <!-- curation:end -->
235
235
  │ └─ No up-front feature knowledge load (avoids confirmation bias in investigators)
236
236
  │
237
237
  ├─ Phase 2: Context gathering
@@ -75,12 +75,12 @@ Pass it as `complianceFrameworks` when invoking the workflow; the engine builds
75
75
 
76
76
  `{integration worktree root}` is the toplevel of the checkout the integration branch is checked out in: `{worktree}` unless the wave runs in a linked worktree.
77
77
 
78
- <!-- learning:on -->
78
+ <!-- curation:on -->
79
79
  **1. Apply decisions context**
80
80
 
81
81
  Apply the `devflow:apply-decisions` algorithm to the DECISIONS_CONTEXT loaded by the decisions step above: scan the index, Read relevant entries, note the verbatim ADR/PF IDs you will inject into Code agent prompts.
82
82
 
83
- <!-- learning:end -->
83
+ <!-- curation:end -->
84
84
  **2. Read budget**
85
85
 
86
86
  Note the `budget` value from the Workflow tool context (or default to "medium" if not provided). This governs Review agent roster size and verification vote count.
@@ -158,9 +158,9 @@ const TICKET = args.ticket || args[0] || "see task description";
158
158
  const PLAN = args.plan || null;
159
159
  const CRITERIA = args.criteria || null;
160
160
  const TEST_PLAN = args.testPlan || null; // the plan's checked TP lines, one string (Pre-authoring step 4)
161
- <!-- learning:on -->
161
+ <!-- curation:on -->
162
162
  const DECISIONS_CONTEXT = args.decisionsContext || ""; // injected before authoring
163
- <!-- learning:end -->
163
+ <!-- curation:end -->
164
164
  const ISSUE_INPUT = args.issueInput || args.issueNumber || "(none)"; // this ticket's OWN raw reference (Pre-authoring step 5; a wave passes issueInput) — setup-task's input, never a Code agent's
165
165
  const ISSUE_REQUIRED = String(args.issueRequired) === "false" ? "false" : "true"; // Pre-authoring step 0; only an explicit false turns it off — absent or unrecognised fails closed, like the resolver
166
166
  const APPLY_CONVENTIONS = String(args.applyConventions) === "false" ? "false" : "true";
@@ -175,7 +175,7 @@ TASK_DESCRIPTION: ${TICKET}
175
175
  ISSUE_REQUIRED: ${ISSUE_REQUIRED}
176
176
  APPLY_CONVENTIONS: ${APPLY_CONVENTIONS}
177
177
  ${ISSUE_INPUT !== "(none)" ? "ISSUE_INPUT: " + ISSUE_INPUT : ""}
178
- Return: {"branch": "<the - **Branch name**: value under your ### Branch, or (none)>", "issueId": "<the - **Issue ID**: value under your ### Handoff Values, or (none)>", "prLinkLine": "<the - **PR link line**: value, or (none)>"}`, { agentType: "Git" })
178
+ Return: {"branch": "<the - **Branch name**: value under your ### Branch, or (none)>", "issueId": "<the - **Issue ID**: value under your ### Handoff Values, or (none)>", "prLinkLine": "<the - **PR link line**: value, or (none)>", "baseSha": "<the 40 or 64 hex git rev-parse HEAD prints before step 4>"}`, { agentType: "Git" })
179
179
  );
180
180
 
181
181
  // The ticket's own Handoff Values, read from setup-task's Output — never derived from ISSUE_INPUT.
@@ -185,6 +185,7 @@ const ISSUE_NUMBER = ISSUE_ID_SHAPE.test(String(setup?.issueId ?? "")) ? setup.i
185
185
  const ISSUE_PR_LINK = setup?.prLinkLine || "(none)"; // "(none)" ⇒ the wave PR carries no closing reference for this ticket
186
186
  // The branch setup-task created, as it reported it: every later phase and the merge use it. The engine never names one.
187
187
  const BRANCH = typeof setup?.branch === "string" && setup.branch.trim() !== "" && setup.branch.trim() !== "(none)" ? setup.branch : "(none)";
188
+ const BASE_SHA = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/.test(String(setup?.baseSha ?? "")) ? setup.baseSha : "(none)"; // the commit the ticket branch was forked from
188
189
 
189
190
  // Ticket-link stop, before implement. The workflow cannot ask, so it never records an exception: it stops.
190
191
  if (ISSUE_REQUIRED === "true" && ISSUE_NUMBER === "(none)") {
@@ -196,6 +197,11 @@ if (BRANCH === "(none)") {
196
197
  return { ticket: TICKET, branch: BRANCH, verdict: "ESCALATED", issueId: ISSUE_NUMBER, issuePrLink: ISSUE_PR_LINK, escalations: [{ type: "branch-missing", description: "setup-task reported no branch name — check its Output, then re-run" }] };
197
198
  }
198
199
 
200
+ // Base stop: every review range starts at the commit the ticket branch was forked from.
201
+ if (BASE_SHA === "(none)") {
202
+ return { ticket: TICKET, branch: BRANCH, verdict: "ESCALATED", issueId: ISSUE_NUMBER, issuePrLink: ISSUE_PR_LINK, escalations: [{ type: "base-missing", description: "setup-task reported no base commit — check its Output, then re-run" }] };
203
+ }
204
+
199
205
  // Phase 2: Implement
200
206
  await phase("implement", () =>
201
207
  agent(`OPERATION: implement
@@ -205,11 +211,11 @@ ${TICKET}
205
211
 
206
212
  ${PLAN ? `Implementation plan:\n${PLAN}` : "No plan provided — use best judgment."}
207
213
 
208
- <!-- learning:on -->
214
+ <!-- curation:on -->
209
215
  Relevant architectural decisions (apply devflow:apply-decisions algorithm):
210
216
  ${DECISIONS_CONTEXT}
211
217
 
212
- <!-- learning:end -->
218
+ <!-- curation:end -->
213
219
  ${COMPLIANCE_DIRECTIVE}
214
220
 
215
221
  When you build or run tests to verify your work, follow your Running commands block.
@@ -244,9 +250,9 @@ Return: {"verdict": "PASS" | "FAIL", "details": "..."}`, { agentType: "Validate"
244
250
  await agent(`OPERATION: validation-fix
245
251
  Fix the validation failures on branch ${BRANCH}:
246
252
  ${failureDetails}
247
- <!-- learning:on -->
253
+ <!-- curation:on -->
248
254
  DECISIONS_CONTEXT: ${DECISIONS_CONTEXT}
249
- <!-- learning:end -->
255
+ <!-- curation:end -->
250
256
  ${COMPLIANCE_DIRECTIVE}
251
257
  Commit fixes with conventional-commit message.`, { agentType: "Fix" });
252
258
  const recheck = await agent(`Re-run build, typecheck, lint, tests on branch ${BRANCH} after fix attempt ${attempt} (follow your Running commands block).
@@ -287,9 +293,9 @@ Return: {"verdict": "PASS" | "FAIL", "rationale": "..."} — FAIL if either answ
287
293
  await agent(`OPERATION: alignment-fix
288
294
  Fix the alignment issues identified by the Evaluate agent on branch ${BRANCH}:
289
295
  ${evaluation?.rationale || "see the Evaluate agent's report"}
290
- <!-- learning:on -->
296
+ <!-- curation:on -->
291
297
  DECISIONS_CONTEXT: ${DECISIONS_CONTEXT}
292
- <!-- learning:end -->
298
+ <!-- curation:end -->
293
299
  ${COMPLIANCE_DIRECTIVE}
294
300
  Self-verify your fix compiles, following your Running commands block. Commit fixes.`, { agentType: "Fix" });
295
301
  evalVerdict = "FAIL-FIXED"; // issues found, fixes applied, not re-evaluated by design
@@ -309,9 +315,9 @@ Cover: functionality, API contracts, performance, and cover every TEST_PLAN scen
309
315
  await agent(`OPERATION: qa-fix
310
316
  Fix the failing acceptance test scenarios on branch ${BRANCH}:
311
317
  ${testResult.failures}
312
- <!-- learning:on -->
318
+ <!-- curation:on -->
313
319
  DECISIONS_CONTEXT: ${DECISIONS_CONTEXT}
314
- <!-- learning:end -->
320
+ <!-- curation:end -->
315
321
  ${COMPLIANCE_DIRECTIVE}
316
322
  Self-verify your fix compiles and the scenarios pass, following your Running commands block. Commit fixes.`, { agentType: "Fix" });
317
323
  testVerdict = "FAIL-FIXED"; // issues found, fixes applied, not re-evaluated by design
@@ -323,10 +329,9 @@ Self-verify your fix compiles and the scenarios pass, following your Running com
323
329
 
324
330
  // Phase 5: Review → verify → fix (single pass)
325
331
  const reviewResult = await phase("review", async () => {
326
- // Review scope: the entire branch diff from the base branch to HEAD. No base SHA is tracked —
327
- // Review agents diff the branch against its merge-base with the default branch.
332
+ // Review scope: the entire branch diff, from the commit the ticket branch was forked from to HEAD.
328
333
  // The pass runs exactly ONCE.
329
- const reviewScope = `Review the full branch diff on branch ${BRANCH}. Diff the branch against its merge-base with the default branch (do not guess a base SHA — compute the merge-base from git).`;
334
+ const reviewScope = `Review the full branch diff on branch ${BRANCH}.\nDIFF_RANGE: ${BASE_SHA}...HEAD\n`;
330
335
 
331
336
  // Review agent focus list (order = index mapping for dead-reviewer detection)
332
337
  const reviewFocuses = ["security", "architecture", "performance", "complexity", "consistency", "regression", "testing", "reliability"];
@@ -370,13 +375,12 @@ Focus discipline: ${focus}. Return: {"focus": "${focus}", "reviewed": true, "fil
370
375
  return { survivingFindings: [], fixedFindings: [], coverageGaps };
371
376
  }
372
377
 
373
- // Adversarial verification — bounded 2-3 agent panel, majority-survives
374
- // Panel asks perspective-diverse questions over the WHOLE finding set (not one agent per finding).
375
- // A finding survives if >50% of panel agents CONFIRM it.
378
+ // Adversarial panel over the WHOLE finding set (not one agent per finding): >50% CONFIRMED survives
376
379
  const VERIFY_PANEL = 3;
377
380
  const panels = await parallel(
378
381
  Array.from({ length: VERIFY_PANEL }, (_, lens) => () =>
379
382
  agent(`Adversarially verify all ${allFindings.length} findings on branch ${BRANCH}.
383
+ DIFF_RANGE: ${BASE_SHA}...HEAD
380
384
  Lens ${lens + 1} of ${VERIFY_PANEL}:
381
385
  ${["Does each finding actually reproduce in the current code? Hunt for findings that describe patterns not present in the diff.",
382
386
  "Is each finding a real issue or a false positive in context? Consider intent, surrounding code, and project conventions.",
@@ -394,16 +398,13 @@ ${JSON.stringify(allFindings.map((f, i) => ({ index: i, description: f.descripti
394
398
  panels.filter(p => (p.verdicts || []).find(v => v.index === i)?.verdict === "CONFIRMED").length > VERIFY_PANEL / 2
395
399
  );
396
400
 
397
- // No confirmed findings — coverageGaps carry forward and block PASS downstream; also eliminates the empty-batch parallel() path
401
+ // No confirmed findings: coverageGaps carry forward and block PASS downstream
398
402
  if (confirmedFindings.length === 0) {
399
403
  return { survivingFindings: [], fixedFindings: [], coverageGaps };
400
404
  }
401
405
 
402
- // Batched fix Code agents — one file per set of sub-batches; max 5 findings per sub-batch.
403
- // Sub-batches for the SAME file run sequentially (never two Code agents editing the same file concurrently —
404
- // concurrent same-file edits cause index contention and lost fixes).
405
- // Sub-batches for DISTINCT files run in parallel (different code areas — safe per concurrency doctrine).
406
- // A finding with no file field gets its own singleton group (unknown scope — never mix with known files).
406
+ // Sub-batches (max 5 findings): same file in sequence, distinct files in parallel.
407
+ // A finding with no file is a singleton group.
407
408
  const MAX_BATCH = 5; // max 5 findings per sub-batch
408
409
  const fileGroups = {};
409
410
  for (let fi = 0; fi < confirmedFindings.length; fi++) {
@@ -413,9 +414,7 @@ ${JSON.stringify(allFindings.map((f, i) => ({ index: i, description: f.descripti
413
414
  fileGroups[key].push(f);
414
415
  }
415
416
 
416
- // One entry per distinct file; each entry runs its sub-batches sequentially.
417
- // Distinct-file groups are paced in chunks of FIX_CHUNK — same pacing bar as the Review spawn
418
- // path — to avoid launching all Code agents at once on a large branch (reliability: explicit bound).
417
+ // One entry per file; FIX_CHUNK chunks bound concurrent Code agents
419
418
  const FIX_CHUNK = 5;
420
419
  // issue-fix SCOPE per finding: CRITICAL or HIGH takes the Careful protocol (failing regression test first); anything else is Standard.
421
420
  const CAREFUL_SEVERITIES = new Set(["critical", "high"]);
@@ -429,9 +428,9 @@ ISSUES:
429
428
  ${chunk.map((f, n) => `${n + 1}. ${f.file ? `${f.file}${f.line ? `:${f.line}` : ""} — ` : ""}${f.description} (${f.severity})`).join("\n")}
430
429
  SCOPE: ${chunk.map((f, n) => `${n + 1}=${CAREFUL_SEVERITIES.has(String(f.severity).toLowerCase()) ? "Careful" : "Standard"}`).join(", ")}
431
430
  PUSH: false
432
- <!-- learning:on -->
431
+ <!-- curation:on -->
433
432
  DECISIONS_CONTEXT: ${DECISIONS_CONTEXT}
434
- <!-- learning:end -->
433
+ <!-- curation:end -->
435
434
  ${COMPLIANCE_DIRECTIVE}
436
435
  Fix all findings in this batch. Self-verify your fix compiles, following your Running commands block. Commit with conventional-commit message.
437
436
  Return: {"status": "fixed"|"blocked", "commitShas": ["<sha>"], "unresolved": ["<description of any finding that could not be fixed>"]}`, { agentType: "Code" });
@@ -490,9 +489,9 @@ Return: {"verdict": "PASS" | "FAIL", "details": "..."}`, { agentType: "Validate"
490
489
  await agent(`OPERATION: validation-fix
491
490
  Fix the final validation failures on branch ${BRANCH}:
492
491
  ${failureDetails}
493
- <!-- learning:on -->
492
+ <!-- curation:on -->
494
493
  DECISIONS_CONTEXT: ${DECISIONS_CONTEXT}
495
- <!-- learning:end -->
494
+ <!-- curation:end -->
496
495
  ${COMPLIANCE_DIRECTIVE}
497
496
  Self-verify your fix compiles. Commit fixes with conventional-commit message.`, { agentType: "Fix" });
498
497
  const recheck = await agent(`Re-run build, typecheck, lint, tests on branch ${BRANCH} (final gate, after fix attempt ${attempt}; follow your Running commands block).
@@ -588,7 +587,7 @@ const results = {}; // ticketId → its row of the workflow's return
588
587
  const rowOf = (ticketId, r, merged, treeEqual = null) => ({ ticket: ticketId, ran: true, verdict: r?.verdict || r?.overallVerdict || null, merged, treeEqual, issuePrLink: r?.issuePrLink || "(none)", evaluateVerdict: r?.gate2?.evaluateVerdict, testVerdict: r?.gate2?.testVerdict, surviving: r?.survivingFindings?.length, coverageComplete: r?.reviewCoverage?.complete });
589
588
  const MAX_ROUNDS = Math.max(10, remainingTickets.length * 2 + 5); // heuristic; always finite
590
589
  const MERGE_SHA = /^[0-9a-f]{40}$/; // a SHA as git prints it; with the checked branch, the only Git-reported values that reach a merge, Validate or undo prompt
591
- const BRANCH_NAME = /^(?![-#]|(?:@|(?:FETCH_|ORIG_|MERGE_)?HEAD)$)(?!.*\.\.)[A-Za-z0-9._/+@,#-]{1,200}$/; // implement's ref allowlist; no leading - or #, no revision name, no ..: the name enters git lines
590
+ const BRANCH_NAME = /^(?![-#]|(?:@|(?:FETCH_|ORIG_|MERGE_)?HEAD)$)(?!.*\.\.)[A-Za-z0-9._/+@,#-]{1,200}$/; // STRICT_NAME_RE's deliberate variant, less its origin/ refusal; the name enters git lines
592
591
  // One ticket's merge, post-merge Validate and undo (D-WAVE-MERGE-VALIDATE: Git validates nothing).
593
592
  const mergeValidateUndo = async (ticketId, engineResult) => {
594
593
  if (typeof engineResult.branch !== "string" || !BRANCH_NAME.test(engineResult.branch)) return { kept: false, reason: "ticket branch name refused: not a plain git ref name", halted: null, treeEqual: null };
@@ -646,11 +645,11 @@ Return: {"ready": [...ticket-ids], "blocked": [{"ticket": "id", "namedBlocker":
646
645
  for (const ticketId of ready) {
647
646
  try {
648
647
  // ticketId is this ticket's OWN ISSUE_REF (pre-fetch heading): the engine's `ticket` and setup-task ISSUE_INPUT; the engine returns the branch setup-task created, merged below; plans[ticketId] is its own plan (Pre-authoring step 4)
649
- <!-- learning:on -->
648
+ <!-- curation:on -->
650
649
  const engineResult = await runSingleTicketEngine({ ticket: ticketId, baseBranch: INTEGRATION_BRANCH, ...(plans[ticketId] || {}), decisionsContext: DECISIONS_CONTEXT, issueRequired: ISSUE_REQUIRED, applyConventions: APPLY_CONVENTIONS, complianceFrameworks: COMPLIANCE_FRAMEWORKS, issueInput: ticketId });
651
- <!-- learning:off -->
650
+ <!-- curation:off -->
652
651
  const engineResult = await runSingleTicketEngine({ ticket: ticketId, baseBranch: INTEGRATION_BRANCH, ...(plans[ticketId] || {}), issueRequired: ISSUE_REQUIRED, applyConventions: APPLY_CONVENTIONS, complianceFrameworks: COMPLIANCE_FRAMEWORKS, issueInput: ticketId });
653
- <!-- learning:end -->
652
+ <!-- curation:end -->
654
653
  // PASS and UNVERIFIED merge (verdict, or overallVerdict as the SINGLE alias); PARTIAL, FAIL, ESCALATED (the ticket-link and branch stops included) or no verdict quarantine.
655
654
  if (["PASS", "UNVERIFIED"].includes(engineResult.verdict || engineResult.overallVerdict)) {
656
655
  const { kept, reason, halted, treeEqual } = await mergeValidateUndo(ticketId, engineResult);
@@ -761,12 +760,14 @@ Do NOT ask questions mid-workflow — that is impossible (F4). The workflow only
761
760
 
762
761
  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.
763
762
 
763
+ **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.
764
+
764
765
  **(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`:
765
766
 
766
767
  ```
767
768
  Agent(subagent_type="Test"):
768
769
  "ORIGINAL_REQUEST: the merged tickets of wave/{slug}, as the wave test plan names them
769
- FILES_CHANGED: {the files wave/{slug} changes against the - **Base**: branch step 6 reported}
770
+ FILES_CHANGED: {the file list that diff printed}
770
771
  TEST_PLAN: {the TP lines of the wave evidence file's ## Test Plan section}
771
772
  WORKTREE_PATH: {integration worktree root}
772
773
  Cover every TEST_PLAN line on the integration branch as it stands. Report PASS or FAIL with evidence."