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
@@ -9,15 +9,11 @@ output-dir: dist/commands
9
9
  @import "./_partials/_settings.mds" as settings
10
10
  # Bug Analysis Command
11
11
 
12
- Run a proactive bug analysis on the current branch by combining static analysis tools with parallel semantic analyzers, then synthesizing results into an actionable bug report.
12
+ Run a proactive bug analysis on the current branch: static analysis tools and parallel semantic analyzers, synthesized into one bug report.
13
13
 
14
14
  ## Usage
15
15
 
16
- ```
17
- /bug-analysis (analyze current branch — incremental if prior analysis exists)
18
- /bug-analysis --full (force full analysis, ignore incremental state)
19
- /bug-analysis --no-static (skip static analysis track, semantic-only)
20
- ```
16
+ `/bug-analysis [--full] [--no-static]`: `--full` ignores incremental state; `--no-static` skips static analysis.
21
17
 
22
18
  ## Phases
23
19
 
@@ -28,7 +24,11 @@ Run a proactive bug analysis on the current branch by combining static analysis
28
24
  {{evidence_policy()}}
29
25
 
30
26
  {{docs_root()}}
27
+ <!-- compliance:off -->
28
+ When `EVIDENCE_POLICY` is `required`, record `TRACEABILITY: DEGRADED (compliance off on this machine; the repository requires evidence)` once, for the Phase 7 report.
29
+ <!-- compliance:end -->
31
30
 
31
+ <!-- compliance:on -->
32
32
  Render the test-plan block from `/implement`'s evidence file, and from nothing else:
33
33
  1. `branch_slug` is `git -C "{worktree}" branch --show-current` with every `/` replaced by `-`.
34
34
  2. Only when `branch_slug` matches `^[A-Za-z0-9._-]{1,200}$` and the file exists, run (the path double-quoted):
@@ -39,12 +39,15 @@ node "$HOME/.devflow/scripts/verify-evidence.cjs" render --plan "{worktree}/.dev
39
39
 
40
40
  3. On `exit=0`, `PR_TEST_PLAN_BLOCK` is its stdout byte for byte without that `exit=` line; in every other case it is `(none)`. Nothing here waits on it: the Git agent pastes it only behind its own check, and only into a PR it creates.
41
41
 
42
+ <!-- compliance:end -->
42
43
  Spawn Git agent:
43
44
 
44
45
  ```
45
46
  Agent(subagent_type="Git", run_in_background=false):
46
47
  "OPERATION: ensure-pr-ready
48
+ <!-- compliance:on -->
47
49
  PR_TEST_PLAN_BLOCK: {PR_TEST_PLAN_BLOCK verbatim, or (none)}
50
+ <!-- compliance:end -->
48
51
  APPLY_CONVENTIONS: {APPLY_CONVENTIONS}
49
52
  Validate branch, commit if needed, push, create PR if needed.
50
53
  Return: branch, base_branch, base_ref, branch-slug, PR#"
@@ -88,7 +91,7 @@ If `pr_number` is absent, set `PR_DESCRIPTION` to `(none)`.
88
91
  CHANGED_FILES=$(git diff --name-only {DIFF_RANGE})
89
92
  ```
90
93
 
91
- Store as `CHANGED_FILES`; Steps 2d and Phase 4 read it. A non-zero diff exit stops.
94
+ Store as `CHANGED_FILES`; Phase 4 reads it. A non-zero diff exit stops.
92
95
 
93
96
  If output is empty → "No changes to analyze." Stop.
94
97
 
@@ -96,75 +99,81 @@ If output is empty → "No changes to analyze." Stop.
96
99
 
97
100
  **Produces:** STATIC_TOOL_STATUS
98
101
 
99
- Skip if `--no-static` flag provided.
102
+ If `--no-static` is set: set `STATIC_FINDINGS` to "Static analysis skipped (--no-static)." and `STATIC_STATUS` to "skipped (--no-static): static analysis did not cover these commits". Skip the rest of Phase 2.
100
103
 
101
104
  ```bash
102
- SEMGREP_AVAILABLE=$(which semgrep 2>/dev/null && echo "yes" || echo "no")
103
- SNYK_AVAILABLE=$(which snyk 2>/dev/null && echo "yes" || echo "no")
104
- CODEQL_AVAILABLE=$(which codeql 2>/dev/null && echo "yes" || echo "no")
105
+ for t in semgrep snyk codeql jq; do printf '%s=%s\n' "$t" "$(command -v "$t" || echo no)"; done
106
+ set -o pipefail; export LC_ALL=C; git -C "{worktree}" diff --name-only -z --diff-filter=d {DIFF_RANGE} | tr '\0\n' '\n?' | sed -n 's/.*\.\([^./]*\)$/\1/p' | sort -u || echo "extension list failed"
105
107
  ```
106
108
 
107
- If all are `no`: warn user "No static analysis tools found. Proceeding with semantic analysis only. To enable static analysis, install semgrep (`pip install semgrep`) or snyk (`npm install -g snyk`)." Set `STATIC_FINDINGS` to `(none)`.
109
+ Its second line lists the extensions of the changed files. `{lang}` is the first of javascript-typescript (js jsx mjs cjs ts tsx), python (py), ruby (rb) whose extension is listed; no other value reaches the command. With none, CodeQL does not run and its status is `no supported language`; `extension list failed` means it did not complete.
110
+
111
+ If all three scanners print `no`: warn user "No static analysis tools found. Install semgrep or snyk." Set `STATIC_FINDINGS` to "Static analysis did not run: no scanner is installed." and `STATIC_STATUS` to `not installed` for each tool.
112
+
113
+ If a scanner is installed but `jq` prints `no`: set `STATIC_FINDINGS` to "Static analysis did not complete: jq is not installed." and `STATIC_STATUS` to `did not complete (jq is not installed)` for an installed tool, else `not installed`.
108
114
 
109
115
  If some are available: note which tools will run.
110
116
 
111
117
  #### Step 2d: Tiered Static Analysis
112
118
 
113
- **Produces:** STATIC_FINDINGS
119
+ **Produces:** STATIC_FINDINGS, STATIC_STATUS
114
120
  **Requires:** STATIC_TOOL_STATUS, DIFF_RANGE, ANALYSIS_DIR
115
121
 
116
- Skip if `--no-static` flag provided or all tools unavailable.
117
-
118
- Run available tools on the changed files (from `CHANGED_FILES` computed in Step 2b).
122
+ Skip if Step 2c set `STATIC_STATUS`.
119
123
 
120
- **Semgrep and Snyk run in parallel** — launch both in the background, then wait for both before proceeding to CodeQL. CodeQL is conditional and sequential.
124
+ Run each available tool in this order, each in its own foreground Bash call with the Bash `timeout` at the ceiling: 600000 ms, or `BASH_MAX_TIMEOUT_MS` when set. Past it, make no tool call, even a Read, until its end notice, then Read the last `exit=` line of the output file that notice names, never a scanner file; the notice sets nothing. File names reach a scanner only through `-z`, `xargs -0` and after `--`.
121
125
 
122
126
  **Semgrep** (if available):
123
127
  ```bash
124
- # tr '\n' '\0' + xargs -0 is portable across GNU and BSD xargs (macOS ships BSD xargs, which lacks -d)
125
- echo "$CHANGED_FILES" | tr '\n' '\0' | xargs -0 timeout 300 semgrep scan --config auto --sarif --quiet 2>/dev/null
128
+ cd "{worktree}" || exit
129
+ set -o pipefail; git diff --name-only -z --diff-filter=d {DIFF_RANGE} | xargs -0 -r semgrep scan --config auto --sarif --quiet -- >"{ANALYSIS_DIR}/semgrep.part" 2>/dev/null; E=$?
130
+ mv "{ANALYSIS_DIR}"/semgrep.{part,sarif}
131
+ printf '\nexit=%s\n' "$E"
126
132
  ```
127
- Parse SARIF output → extract findings.
128
133
 
129
134
  **Snyk Code** (if available):
130
135
  ```bash
131
- # One project-level scan (a per-file xargs run would invoke snyk O(n) times; --file is for dependency scans).
132
- SNYK_SARIF=$(timeout 300 snyk code test --sarif 2>/dev/null)
133
- # Programmatic filter: keep only results whose file path is in CHANGED_FILES — defense-in-depth, before the LLM agent sees any output.
134
- SNYK_FILTERED=$(echo "$SNYK_SARIF" | jq --argjson files "$(echo "$CHANGED_FILES" | jq -R . | jq -s .)" \
135
- '.runs[].results |= map(select(.locations[].physicalLocation.artifactLocation.uri as $uri | $files | index($uri) != null))' \
136
- 2>/dev/null || echo "$SNYK_SARIF")
136
+ cd "{worktree}" || exit
137
+ snyk code test --sarif >"{ANALYSIS_DIR}/snyk-all.json" 2>/dev/null; E=$?
138
+ git diff --name-only -z {DIFF_RANGE} >"{ANALYSIS_DIR}/changed.z" && jq --rawfile n "{ANALYSIS_DIR}/changed.z" \
139
+ '($n|split("\u0000")) as $f|.runs[]?.results|=[.[]?|select([.locations[]?.physicalLocation.artifactLocation.uri//empty] as $u|($u|length)==0 or any($u[];IN($f[])))]' \
140
+ "{ANALYSIS_DIR}/snyk-all.json" >"{ANALYSIS_DIR}/snyk.sarif" \
141
+ && jq -nr '[inputs|[.runs[]?.results[]?]|length]|"total=\(.[0]) kept=\(.[1])"' "{ANALYSIS_DIR}/snyk-all.json" "{ANALYSIS_DIR}/snyk.sarif" \
142
+ || { echo "Snyk scope filter failed: unfiltered"; cp "{ANALYSIS_DIR}/snyk-all.json" "{ANALYSIS_DIR}/snyk.sarif"; }
143
+ printf '\nexit=%s\n' "$E"
137
144
  ```
138
- Parse `SNYK_FILTERED` SARIF → extract findings. If `jq` is unavailable, fall back to the raw `SNYK_SARIF` and note the limitation.
145
+
146
+ **Counts and table** (after Snyk with `{tools}` = `semgrep snyk`; after CodeQL with `codeql`):
147
+ ```bash
148
+ cd "{ANALYSIS_DIR}" || exit
149
+ L='def L($r):.ruleId as $i|.level//([$r.tool|.driver,.extensions[]?|.rules[]?|select(.id==$i)]|.[0].defaultConfiguration.level)//"warning";'
150
+ for t in {tools}; do [ -f $t.sarif ] || continue
151
+ jq -rs --arg t $t "$L"'[.[].runs[]?|. as $r|.results[]?|L($r)] as $l|def c(k):[$l[]|select(.==k)]|length;"\($t) docs=\(length) results=\($l|length) error=\(c("error")) warning=\(c("warning")) note=\(c("note"))"' $t.sarif || echo "$t sarif=unreadable"
152
+ jq -r --arg t $t "$L"'.runs[]?|. as $r|.results[]?|[$t,(.locations[0].physicalLocation|.artifactLocation.uri,.region.startLine),L($r),(.ruleId//"—"),((.message.text//"")[:200])]|@tsv' $t.sarif >findings-$t.tsv || echo "findings table incomplete: $t"
153
+ done
154
+ cat findings-{semgrep,snyk,codeql}.tsv >findings.tsv 2>/dev/null
155
+ jq -Rrs 'split("\n")|map(select(.!=""))|sort_by(split("\t")[3]|{error:0,warning:1}[.]//2)|.[:50][]' findings.tsv >findings-top.tsv || echo "findings table incomplete: top"
156
+ ```
157
+ Read `error` as HIGH, `warning` as MEDIUM, `note` as LOW.
139
158
 
140
159
  **CodeQL** (if available AND (`--full` OR Semgrep/Snyk found HIGH/CRITICAL findings)):
141
160
  ```bash
142
- # Use a unique temp directory per run to prevent symlink attacks and concurrent-process clobbering
143
- CODEQL_TMP=$(mktemp -d)
144
- # Register cleanup trap immediately after mktemp — ensures rm -rf runs on EXIT, SIGTERM, and SIGINT
145
- # even if the session is interrupted before reaching the explicit rm -rf below
161
+ CODEQL_TMP=$(mktemp -d) || exit
146
162
  trap 'rm -rf "${CODEQL_TMP}"' EXIT INT TERM
147
- timeout 600 codeql database create "${CODEQL_TMP}/db" --language={detected-language} --source-root=. 2>/dev/null && \
148
- timeout 600 codeql database analyze "${CODEQL_TMP}/db" --format=sarif-latest --output="${CODEQL_TMP}/results.sarif" 2>/dev/null
149
- # Capture exit status before cleanup so cleanup doesn't mask failures
163
+ { codeql database create "${CODEQL_TMP}/db" --language={lang} --source-root="{worktree}" && \
164
+ codeql database analyze "${CODEQL_TMP}/db" --format=sarif-latest --output="{ANALYSIS_DIR}/codeql.sarif"; } >"{ANALYSIS_DIR}/codeql.log" 2>&1
150
165
  CODEQL_EXIT=$?
151
- # Parse SARIF output BEFORE cleanup — rm -rf destroys results.sarif
152
- CODEQL_SARIF=$(cat "${CODEQL_TMP}/results.sarif" 2>/dev/null || echo "")
153
- # Explicit cleanup (trap also covers this path; explicit rm is belt-and-suspenders)
166
+ printf '\nexit=%s\n' "$CODEQL_EXIT"
154
167
  rm -rf "${CODEQL_TMP}"
155
168
  trap - EXIT INT TERM
156
169
  ```
157
- Parse `CODEQL_SARIF` → extract findings. If database creation fails, `CODEQL_EXIT` is non-zero — skip CodeQL findings and note it. The `trap` guarantees cleanup on SIGTERM/SIGINT/EXIT so orphaned temp directories do not accumulate across interrupted sessions.
170
+ A tool's status is its last line, `exit={n}`; a tool that ran completed only on Semgrep 0, Snyk 0 or 1 (1 = issues, only with SARIF output), CodeQL 0. Snyk 3 (no supported file) is `no supported language`: its counts are not checked. Any other status, or no such line, means it did not complete (126-127: scanner did not start; else failed. Semgrep via xargs: number only). A call with no `exit=` line read did not complete. A tool that ran also did not complete when the counts fence prints no `{tool} docs=` line for it, `sarif=unreadable` or `findings table incomplete` for it (`: top` counts for every tool), or `docs=0` (Semgrep exit 0 with `docs=0`: no file to scan, completed).
158
171
 
159
- **Normalize** all findings to unified table, cap at top 50 by severity. Truncate each Description entry to 200 characters maximum:
172
+ `findings.tsv` keeps every finding. Read only `findings-top.tsv` (top 50 by level: tool, file, line, level, rule, message cut to 200 chars), set `STATIC_FINDINGS` to the column names and its rows, and write them with the status lines to `{ANALYSIS_DIR}/static-findings.md`.
160
173
 
161
- | Tool | File:Line | CWE | Severity | Title | Description |
162
- |------|-----------|-----|----------|-------|-------------|
163
- | {tool} | {file}:{line} | {CWE or —} | {CRITICAL/HIGH/MEDIUM/LOW} | {title} | {description truncated to 200 chars} |
174
+ `STATIC_FINDINGS` is `(none)` only when every tool that was to run completed, at least one did, and none found anything; when no tool was to run, it is "Static analysis did not run: no tool ran." For each tool that did not complete, add under any rows the line "Static analysis did not complete: {tool}: " plus "exit {n} ({meaning}).", "no exit status.", "no counts line." or "SARIF not read." A Snyk call (not Snyk 3) that printed "Snyk scope filter failed: unfiltered" adds that line too.
164
175
 
165
- Write ALL raw findings to `{ANALYSIS_DIR}/static-findings.md`. Set `STATIC_FINDINGS` to the top-50 table.
166
-
167
- If no tool produced findings: set `STATIC_FINDINGS` to `(none)`.
176
+ Set `STATIC_STATUS` to one `{tool}: {value}` per tool: `completed`, `not installed`, `not needed` (CodeQL, not triggered) or `no supported language` (CodeQL with no table row, or Snyk 3), all covered, or `did not complete ({why})`, not covered. A covered tool other than `completed` was not to run.
168
177
 
169
178
  ### Phase 3: Context Loading
170
179
 
@@ -188,23 +197,22 @@ If no tool produced findings: set `STATIC_FINDINGS` to `(none)`.
188
197
  #### Plan Artifact
189
198
 
190
199
  1. List the design plans: `{worktree}/.devflow/docs/design/*.md` (a `/plan` artifact) and `{worktree}/.devflow/docs/design/*/*/*-plan.md` (a `/dynamic-plan` per-ticket plan). Sort by timestamp, newest first, and scan the 10 most recent. A `/plan` artifact's timestamp is the `YYYY-MM-DD_HHMM` before its `.md`; a per-ticket plan's is the name of its parent directory. Never sort by file name, which starts with an issue ID or a ticket slug. A per-ticket plan counts only when its `{ticket-slug}` (its file name without `-plan.md`) appears in the worktree's branch name
191
- 2. Read the most recent file that carries an `## Acceptance Criteria` section
192
- 3. Extract `## Acceptance Criteria` section → parse into table: `| ID | Criterion | Type | Testable Condition |`
193
- 4. Set `PLAN_CONTEXT` to plan summary; `ACCEPTANCE_RULES` to the table
194
- 5. If no plan files exist or section not found: `PLAN_CONTEXT=(none)`, `ACCEPTANCE_RULES=(none)`
200
+ 2. Read the most recent file that carries an `## Acceptance Criteria` section; parse it into the table `| ID | Criterion | Type | Testable Condition |`
201
+ 3. Set `PLAN_CONTEXT` to plan summary; `ACCEPTANCE_RULES` to the table
202
+ 4. If no plan files exist or section not found: `PLAN_CONTEXT=(none)`, `ACCEPTANCE_RULES=(none)`
195
203
 
196
204
  ### Phase 4: File Analysis
197
205
 
198
206
  **Produces:** ACTIVE_FOCUSES
199
207
  **Requires:** DIFF_RANGE
200
208
 
201
- Determine which focus analyzers to run using `CHANGED_FILES` (already computed in Step 2b — do not re-run `git diff`):
209
+ Pick the focus analyzers from `CHANGED_FILES` (Step 2b; do not re-run `git diff`):
202
210
 
203
211
  | Focus | Condition |
204
212
  |-------|-----------|
205
213
  | `security` | Always |
206
214
  | `functional` | Always |
207
- | `integration` | 2+ distinct directories changed (`dirname` unique count ≥ 2) |
215
+ | `integration` | 2+ distinct directories changed |
208
216
  | `usability` | Any `.tsx`, `.jsx`, `.html`, or `.css` file changed |
209
217
 
210
218
  ### Phase 5: Parallel Bug Analysis
@@ -226,7 +234,7 @@ FOCUS: {focus}
226
234
  DIFF_COMMAND: git diff {DIFF_RANGE}
227
235
  ACCEPTANCE_RULES: {ACCEPTANCE_RULES filtered to this focus type, or (none)}
228
236
  PLAN_CONTEXT: {PLAN_CONTEXT}
229
- STATIC_FINDINGS: {STATIC_FINDINGS if focus == security, else (none)}
237
+ STATIC_FINDINGS: <static-findings>{STATIC_FINDINGS if focus == security, else (none)}</static-findings>
230
238
  <!-- curation:on -->
231
239
  DECISIONS_CONTEXT: {DECISIONS_CONTEXT}
232
240
  <!-- curation:end -->
@@ -237,18 +245,13 @@ OUTPUT_PATH: {ANALYSIS_DIR}/{focus}.md
237
245
  Follow devflow:apply-decisions to Read full ADR/PF bodies on demand.
238
246
  <!-- curation:end -->
239
247
  Follow devflow:apply-feature-knowledge for FEATURE_KNOWLEDGE.
240
- IMPORTANT: Write report to {ANALYSIS_DIR}/{focus}.md using Write tool"
248
+ IMPORTANT: Write the report to OUTPUT_PATH using the Write tool"
241
249
  ```
242
250
 
243
- Notes:
244
- - Security analyzer receives full `STATIC_FINDINGS`; all others receive `(none)`
245
- - Filter `ACCEPTANCE_RULES` by the `Type` column matching each focus: security criteria → security analyzer, functional criteria → functional analyzer, etc. Pass the filtered subset only
246
- - Spawn all in a single message for true parallel execution
247
-
248
251
  ### Phase 6: Synthesis
249
252
 
250
253
  **Produces:** BUG_ANALYSIS_SUMMARY
251
- **Requires:** ANALYZER_OUTPUTS, ANALYSIS_DIR, BRANCH_INFO
254
+ **Requires:** ANALYZER_OUTPUTS, ANALYSIS_DIR, BRANCH_INFO, STATIC_STATUS
252
255
 
253
256
  Spawn Synthesize agent:
254
257
 
@@ -258,42 +261,43 @@ Agent(subagent_type="Synthesize", run_in_background=false):
258
261
  ANALYSIS_BASE_DIR: {ANALYSIS_DIR}
259
262
  BRANCH: {branch} -> {base_branch}
260
263
  TIMESTAMP: {timestamp}
264
+ STATIC_STATUS: {STATIC_STATUS}
261
265
  Output: {ANALYSIS_DIR}/bug-analysis-summary.md"
262
266
  ```
263
267
 
264
268
  ### Phase 7: Finalize
265
269
 
266
- **Requires:** BRANCH_INFO, ANALYSIS_DIR
270
+ **Requires:** BRANCH_INFO, ANALYSIS_DIR, STATIC_STATUS
267
271
 
268
- 1. In one Bash call run `M="$(git -C "{worktree}" rev-parse --absolute-git-dir)/devflow/bug-analysis/{branch-slug}" && mkdir -p "$M" && git -C "{worktree}" rev-parse HEAD > "$M/.last-analysis-head"`. A failed or refused write never stops the run and is not retried another way.
272
+ 1. Run the write below only when every tool that was to run completed, or `--no-static` is set, also with `--full`. Else keep the marker; the report names the way out (fix the tool, or run with `--no-static`). In one Bash call run `M="$(git -C "{worktree}" rev-parse --absolute-git-dir)/devflow/bug-analysis/{branch-slug}" && mkdir -p "$M" && git -C "{worktree}" rev-parse HEAD > "$M/.last-analysis-head"`. A failed or refused write never stops the run and is not retried another way.
269
273
  2. Report to user:
270
274
 
271
275
  ```
272
276
  ## Bug Analysis Complete
273
277
 
274
278
  **Branch**: {branch} -> {base_branch}
279
+ <!-- compliance:on -->
275
280
  {any base `TRACEABILITY: DEGRADED` line from Phase 1, as returned}
281
+ <!-- compliance:off -->
282
+ {any base `TRACEABILITY: DEGRADED` line from Phase 1, as returned, and the compliance-off line of Phase 1}
283
+ <!-- compliance:end -->
276
284
  **Analysis**: {ANALYSIS_DIR}
285
+ **Static analysis**: {STATIC_STATUS per tool; if a tool did not complete: "marker kept" and the way out; any Snyk filter note}
277
286
 
278
287
  ### Risk Assessment: {risk_level}
279
288
 
280
289
  {brief_reasoning}
281
290
 
282
291
  ### Bug Counts
283
- | Category | CRITICAL | HIGH | MEDIUM | LOW | Total |
284
- |----------|----------|------|--------|-----|-------|
285
- | Security | {n} | {n} | {n} | {n} | {n} |
286
- | Functional | {n} | {n} | {n} | {n} | {n} |
287
- | Integration | {n} | {n} | {n} | {n} | {n} |
288
- | Usability | {n} | {n} | {n} | {n} | {n} |
292
+ {The summary's Bug Summary table: Security, Functional, Integration and Usability rows by CRITICAL, HIGH, MEDIUM, LOW and Total}
289
293
 
290
294
  ### Top Findings
291
- {List top 3-5 bugs by severity and confidence}
295
+ {Top 3-5 bugs by severity and confidence}
292
296
 
293
297
  ### Artifacts
294
298
  - Bug report: {ANALYSIS_DIR}/bug-analysis-summary.md
295
- - Per-focus reports: {ANALYSIS_DIR}/{security|functional|integration|usability}.md
296
- - Static findings: {ANALYSIS_DIR}/static-findings.md (if static analysis ran)
299
+ - Per-focus reports: {ANALYSIS_DIR}/{focus}.md
300
+ - Static findings: {ANALYSIS_DIR}/static-findings.md (if it ran)
297
301
 
298
302
  {if any CRITICAL or HIGH bugs found:}
299
303
  Run `/resolve` to process and fix these findings.
@@ -301,76 +305,26 @@ Run `/resolve` to process and fix these findings.
301
305
 
302
306
  ## Architecture
303
307
 
304
- ```
305
- /bug-analysis (orchestrator — spawns agents only)
306
- │
307
- ├─ Phase 1: Pre-flight
308
- │ └─ Git agent (ensure-pr-ready)
309
- │
310
- ├─ Phase 2: Static Analysis
311
- │ └─ 2a incremental range, 2b changed files (stop if none), 2c tools, 2d semgrep → snyk → codeql
312
- │
313
- ├─ Phase 3: Context Loading
314
- <!-- curation:on -->
315
- │ ├─ index.md (pre-rendered) → DECISIONS_CONTEXT
316
- <!-- curation:end -->
317
- │ ├─ Feature knowledge load → FEATURE_KNOWLEDGE
318
- │ └─ {worktree}/.devflow/docs/design/*.md → PLAN_CONTEXT + ACCEPTANCE_RULES
319
- │
320
- ├─ Phase 4: File Analysis
321
- │ └─ Detect active focuses (security + functional always; integration + usability conditional)
322
- │
323
- ├─ Phase 5: Bug Analysis (PARALLEL)
324
- │ └─ Debug agent per active focus (security also reads STATIC_FINDINGS)
325
- │
326
- ├─ Phase 6: Synthesis
327
- │ └─ Synthesize agent (mode: bug-analysis)
328
- │
329
- └─ Phase 7: Finalize
330
- ├─ Write .last-analysis-head
331
- └─ Display results + suggest /resolve if blocking bugs found
332
- ```
308
+ Seven phases: Phase 1 to Phase 7.
333
309
 
334
310
  ## Edge Cases
335
311
 
336
312
  | Case | Handling |
337
313
  |------|----------|
338
- | No new commits since last analysis | Stop: "No new commits since last analysis. Use --full for a full re-analysis." |
339
314
  | Rebase invalidates `.last-analysis-head` SHA | `git cat-file -t` check fails → fallback to full diff |
340
315
  | Zero changed files in DIFF_RANGE with exit 0 | Stop: "No changes to analyze." |
341
- | Same-minute analysis collision | `mkdir` with seconds suffix (`YYYY-MM-DD_HHMMSS`) |
342
- | All static tools unavailable | Warn, proceed with semantic-only analysis |
343
- | `--no-static` flag | Skip Phase 2c and 2d entirely; `STATIC_FINDINGS=(none)` |
344
316
  | `--full` flag | Bypass incremental detection (Step 2a), run full diff from base |
345
- | CodeQL database creation fails | Skip CodeQL, note in output, continue with other tools |
317
+ | A scanner did not run or did not complete | Name the tool and why in `STATIC_FINDINGS`, not `(none)`; a tool that did not complete keeps the marker |
346
318
 
347
319
  ## Resolve Compatibility
348
320
 
349
- Run `/resolve` after `/bug-analysis` to fix identified bugs. `/resolve` automatically detects and uses bug analysis reports when no code review report exists.
321
+ `/resolve` detects and uses bug analysis reports when no code review report exists.
350
322
 
351
323
  ## Principles
352
324
 
353
- 1. **Orchestration only** — Command spawns agents, doesn't do analysis work itself
354
- 2. **Parallel, not background** — Analyzers spawn in one message with `run_in_background=false`
355
- 3. **Static + semantic** — Two complementary tracks, each validates the other
356
- 4. **Incremental by default** — Only analyze new changes unless `--full` specified
357
- 5. **Verify before reporting** — Debug agents self-verify every finding
358
- 6. **Honest reporting** — Display risk level and counts directly from synthesis
325
+ 1. **Orchestration only** — the command spawns agents and does no analysis itself
326
+ 2. **Incremental by default** — only new changes, unless `--full`
359
327
 
360
328
  ## Phase Completion Checklist
361
329
 
362
- Before reporting results, verify every phase was executed:
363
-
364
- - [ ] Phase 1: Pre-flight → BRANCH_INFO captured, PR_DESCRIPTION fetched (or `(none)`)
365
- - [ ] Phase 2: Static Analysis → STATIC_FINDINGS captured (or `(none)` if skipped/no tools/no findings); ANALYSIS_DIR created; CHANGED_FILES populated
366
- <!-- curation:on -->
367
- - [ ] Phase 3: Context Loading → DECISIONS_CONTEXT captured, FEATURE_KNOWLEDGE loaded (or `(none)`), PLAN_CONTEXT and ACCEPTANCE_RULES captured (or `(none)`)
368
- <!-- curation:off -->
369
- - [ ] Phase 3: Context Loading → FEATURE_KNOWLEDGE loaded (or `(none)`), PLAN_CONTEXT and ACCEPTANCE_RULES captured (or `(none)`)
370
- <!-- curation:end -->
371
- - [ ] Phase 4: File Analysis → ACTIVE_FOCUSES determined (security + functional always present)
372
- - [ ] Phase 5: Parallel Bug Analysis → ANALYZER_OUTPUTS captured per active focus; all reports written to ANALYSIS_DIR
373
- - [ ] Phase 6: Synthesis → BUG_ANALYSIS_SUMMARY written to `{ANALYSIS_DIR}/bug-analysis-summary.md`
374
- - [ ] Phase 7: Finalize → `.last-analysis-head` updated; results displayed to user
375
-
376
- If any phase is unchecked, execute it before proceeding.
330
+ Before reporting results, verify that every phase ran and that each variable it produces is captured, with STATIC_FINDINGS (`(none)` only if every tool that was to run completed clean), the report files in ANALYSIS_DIR present and `.last-analysis-head` written only if Phase 7's gate allows; run any missing phase first.
@@ -10,7 +10,11 @@ output-dir: dist/commands
10
10
  @import "./_partials/_settings.mds" as settings
11
11
  # Code Review Command
12
12
 
13
+ <!-- compliance:on -->
13
14
  Run a comprehensive code review of the current branch by spawning parallel review agents, then synthesizing results into PR comments.
15
+ <!-- compliance:off -->
16
+ Run a comprehensive code review of the current branch by spawning parallel review agents, then synthesizing results into a local review summary.
17
+ <!-- compliance:end -->
14
18
 
15
19
  ## Usage
16
20
 
@@ -52,6 +56,9 @@ Keep each worktree's values for every downstream phase.
52
56
  **Produces:** EVIDENCE_POLICY, ISSUE_REQUIRED, APPLY_CONVENTIONS, REQUIRE_NON_AUTHOR_APPROVAL
53
57
 
54
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 Phase 4 report.
61
+ <!-- compliance:end -->
55
62
 
56
63
  #### Step 0c: Per-Worktree Pre-Flight (Git Agent)
57
64
 
@@ -64,6 +71,7 @@ Discover PR description guidance from plan artifact (per worktree):
64
71
  3. Read the most recent file that carries the section, extract `## PR Description Guidance` section
65
72
  4. If no plan files exist or section not found, set `PR_DESCRIPTION_GUIDANCE` to `(none)`
66
73
 
74
+ <!-- compliance:on -->
67
75
  Render the test-plan block (per worktree) from `/implement`'s evidence file, and from nothing else:
68
76
  1. `branch_slug` is `git -C "{worktree}" branch --show-current` with every `/` replaced by `-`.
69
77
  2. Only when `branch_slug` matches `^[A-Za-z0-9._-]{1,200}$` and the file exists, run (the path double-quoted):
@@ -74,6 +82,7 @@ node "$HOME/.devflow/scripts/verify-evidence.cjs" render --plan "{worktree}/.dev
74
82
 
75
83
  3. On `exit=0`, `PR_TEST_PLAN_BLOCK` is its stdout byte for byte without that `exit=` line; in every other case it is `(none)`. Nothing here waits on it: the Git agent pastes it only behind its own check, and only into a PR it creates.
76
84
 
85
+ <!-- compliance:end -->
77
86
  For each reviewable worktree, spawn Git agent:
78
87
 
79
88
  ```
@@ -81,7 +90,9 @@ Agent(subagent_type="Git", run_in_background=false):
81
90
  "OPERATION: ensure-pr-ready
82
91
  WORKTREE_PATH: {worktree_path} (omit if cwd)
83
92
  PR_DESCRIPTION_GUIDANCE: {pr_description_guidance}
93
+ <!-- compliance:on -->
84
94
  PR_TEST_PLAN_BLOCK: {PR_TEST_PLAN_BLOCK verbatim, or (none)}
95
+ <!-- compliance:end -->
85
96
  APPLY_CONVENTIONS: {APPLY_CONVENTIONS}
86
97
  Validate branch, commit if needed, push, create PR if needed.
87
98
  Return: branch, base_branch, base_ref, branch-slug, PR#"
@@ -158,6 +169,7 @@ MAX_REVIEW_CYCLES = 10
158
169
  | denominator = 0 OR parsing failed | fp_ratio = 0, skip warning (degraded note on parse failure) |
159
170
  | fp_ratio > 0.7 AND CYCLE_NUMBER >= 3 | Warn in output, continue |
160
171
 
172
+ <!-- compliance:on -->
161
173
  #### Step 0f: Resolve Publication Mode (Per Worktree)
162
174
 
163
175
  **Produces:** REVIEW_PUBLICATION
@@ -167,6 +179,7 @@ For each reviewable worktree, call:
167
179
 
168
180
  {{publication_gate()}}
169
181
 
182
+ <!-- compliance:end -->
170
183
  ### Phase 1: Analyze Changed Files
171
184
 
172
185
  **Produces:** REVIEW_FOCUS_LIST, DIFF_CLASS, DIFF_FILES
@@ -371,12 +384,22 @@ IMPORTANT: Write report to {worktree_path}/.devflow/docs/reviews/{branch-slug}/{
371
384
 
372
385
  In multi-worktree mode, process worktrees **sequentially**: Phases 1-4 for each.
373
386
 
387
+ <!-- compliance:on -->
374
388
  ### Phase 3: Synthesis → Review Comment (Sequential)
375
389
 
376
390
  **Produces:** REVIEW_SUMMARY, PR_COMMENT
391
+ <!-- compliance:off -->
392
+ ### Phase 3: Synthesis → Review Summary (Sequential)
393
+
394
+ **Produces:** REVIEW_SUMMARY
395
+ <!-- compliance:end -->
377
396
  **Requires:** REVIEW_FOCUS_OUTPUTS, REVIEW_DIR, PR_INFO, GATE_LEVEL, REVIEW_FOCUS_LIST
378
397
 
398
+ <!-- compliance:on -->
379
399
  **WAIT** for Phase 2. For each worktree, run steps 3a and 3b in sequence:
400
+ <!-- compliance:off -->
401
+ **WAIT** for Phase 2. For each worktree, run step 3a:
402
+ <!-- compliance:end -->
380
403
 
381
404
  **Step 3a — Synthesize agent** per worktree:
382
405
  ```
@@ -394,6 +417,7 @@ Aggregate findings, determine merge recommendation.
394
417
  Output: {worktree_path}/.devflow/docs/reviews/{branch-slug}/{timestamp}/review-summary.md"
395
418
  ```
396
419
 
420
+ <!-- compliance:on -->
397
421
  **Step 3b — Git agent (post-review-summary)** per worktree (after Step 3a writes review-summary.md):
398
422
  ```
399
423
  Agent(subagent_type="Git", run_in_background=false):
@@ -407,6 +431,7 @@ WORKTREE_PATH: {worktree_path} (omit if cwd)
407
431
  Posts the consolidated review-summary comment (marker-deduped on the cycle+timestamp pair)."
408
432
  ```
409
433
 
434
+ <!-- compliance:end -->
410
435
  ### Phase 4: Write Review Head Marker & Report
411
436
 
412
437
  **Requires:** BRANCH_INFO, REVIEW_DIR
@@ -416,9 +441,14 @@ Per worktree, after successful completion:
416
441
  2. Display results from all agents:
417
442
  - Merge recommendation (from Synthesize agent)
418
443
  - Issue counts by category (🔴 blocking / ⚠️ should-fix / ℹ️ pre-existing)
444
+ <!-- compliance:on -->
419
445
  - Review comment status: POSTED / POSTED+TRUNCATED (body exceeded 60k after redaction) / SKIPPED (D7 dedup) / DEGRADED (from Git)
420
446
  - 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
447
  - Any base `TRACEABILITY: DEGRADED` line from Step 0c, as returned
448
+ <!-- compliance:off -->
449
+ - Review summary: `.devflow/docs/reviews/{branch-slug}/{timestamp}/review-summary.md` (local; not posted)
450
+ - Any base `TRACEABILITY: DEGRADED` line from Step 0c, as returned, and the compliance-off line of Step 0b-ii
451
+ <!-- compliance:end -->
422
452
  - Artifact paths
423
453
 
424
454
  ## Architecture
@@ -426,7 +456,11 @@ Per worktree, after successful completion:
426
456
  ```
427
457
  /code-review
428
458
  │
459
+ <!-- compliance:on -->
429
460
  ├─ Phase 0: Worktree Discovery & Pre-flight, Steps 0a-0f (Git agent per worktree, parallel)
461
+ <!-- compliance:off -->
462
+ ├─ Phase 0: Worktree Discovery & Pre-flight, Steps 0a-0e (Git agent per worktree, parallel)
463
+ <!-- compliance:end -->
430
464
  │ ├─ Step 0b: Resolve the compliance lens and gate level
431
465
  │
432
466
  ├─ Per worktree (SEQUENTIAL):
@@ -440,9 +474,14 @@ Per worktree, after successful completion:
440
474
  │ │ ├─ code: core (diff.patch), language (diff-{focus}.patch), conditional
441
475
  │ │ └─ docs-only / tests-only / lockfile-only: the reduced set (diff.patch)
442
476
  │ │
477
+ <!-- compliance:on -->
443
478
  │ ├─ Phase 3: Synthesis → Review Comment (SEQUENTIAL within worktree)
444
479
  │ │ ├─ Step 3a: Synthesize agent (mode: review, writes review-summary.md)
445
480
  │ │ └─ Step 3b: Git agent (post-review-summary)
481
+ <!-- compliance:off -->
482
+ │ ├─ Phase 3: Synthesis → Review Summary (SEQUENTIAL within worktree)
483
+ │ │ └─ Step 3a: Synthesize agent (mode: review, writes review-summary.md)
484
+ <!-- compliance:end -->
446
485
  │ │
447
486
  │ └─ Phase 4: Write .last-review-head + display results
448
487
  ```
@@ -452,7 +491,9 @@ Per worktree, after successful completion:
452
491
  | Case | Handling |
453
492
  |------|----------|
454
493
  | `--full` in multi-worktree mode | Applies to all worktrees (global modifier). It sets the diff range, never the gate level |
494
+ <!-- compliance:on -->
455
495
  | Review comment already posted | Git agent matches its own marker on the `{cycle, timestamp}` pair → skip silently (D7) |
496
+ <!-- compliance:end -->
456
497
  | Docs-only diff | Its Step 1.1 set, narrowed by level |
457
498
  | Tests-only diff | Its Step 1.1 set, narrowed by level |
458
499
  | Lockfile-only diff | Its Step 1.1 set, narrowed by level |
@@ -461,7 +502,9 @@ Per worktree, after successful completion:
461
502
  | A file moved across classes | `--no-renames` lists both paths, so a code path makes the diff `code` |
462
503
  | Path listing above about 40 lines | Read in ranges (Step 1.1) |
463
504
  | Language files changed, plugin not installed | The focus is absent from the stamped line: not spawned |
505
+ <!-- compliance:on -->
464
506
  | `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 |
507
+ <!-- compliance:end -->
465
508
 
466
509
  ## Backwards Compatibility
467
510