devflow-kit 3.9.0 → 3.10.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.
- package/CHANGELOG.md +111 -0
- package/README.md +1 -1
- package/dist/agents/code.md +6 -6
- package/dist/agents/fix.md +6 -6
- package/dist/agents/harden.md +7 -6
- package/dist/agents/refactor.md +6 -6
- package/dist/cli/commands/ambient.js +10 -2
- package/dist/cli/commands/compliance-prompts.js +9 -4
- package/dist/cli/commands/compliance.js +171 -24
- package/dist/cli/commands/curation.js +12 -7
- package/dist/cli/commands/gate-level-prompts.js +39 -25
- package/dist/cli/commands/gates.js +5 -7
- package/dist/cli/commands/init.js +142 -138
- package/dist/cli/commands/install-report.js +34 -0
- package/dist/cli/commands/legacy-sweep.js +64 -0
- package/dist/cli/commands/proxy.js +6 -1
- package/dist/cli/commands/rules.js +29 -12
- package/dist/cli/commands/skills.js +42 -9
- package/dist/cli/commands/tracker.js +9 -3
- package/dist/cli/commands/uninstall.js +277 -51
- package/dist/commands/bug-analysis.md +69 -120
- package/dist/commands/dynamic-build.md +23 -23
- package/dist/commands/implement.md +46 -32
- package/dist/commands/release.md +1 -1
- package/dist/commands/resolve.md +35 -31
- package/dist/commands/self-review.md +8 -7
- package/dist/compliance-off/agents/git.md +120 -0
- package/dist/compliance-off/agents/triage.md +180 -0
- package/dist/compliance-off/commands/bug-analysis.md +398 -0
- package/dist/compliance-off/commands/code-review.md +520 -0
- package/dist/compliance-off/commands/dynamic-build.md +1251 -0
- package/dist/compliance-off/commands/dynamic-tickets.md +676 -0
- package/dist/compliance-off/commands/implement.md +736 -0
- package/dist/compliance-off/commands/plan.md +671 -0
- package/dist/compliance-off/commands/release.md +309 -0
- package/dist/compliance-off/commands/resolve.md +742 -0
- package/dist/compliance-off/skills/git/references/decision-markers.md +17 -0
- package/dist/compliance-off/skills/git/references/learn-conventions.md +80 -0
- package/dist/compliance-off/skills/git/references/pr/check-ci-status.md +33 -0
- package/dist/compliance-off/skills/git/references/pr/check-merge-readiness.md +49 -0
- package/dist/compliance-off/skills/git/references/pr/fetch-review-threads.md +52 -0
- package/dist/compliance-off/skills/git/references/pr/validate-branch.md +47 -0
- package/dist/compliance-off/skills/git/references/tracker/_contract.md +33 -0
- package/dist/compliance-off/skills/git/references/tracker/_mcp.md +153 -0
- package/dist/compliance-off/skills/git/references/tracker/github/create-release.md +35 -0
- package/dist/compliance-off/skills/git/references/tracker/github/ensure-pr-ready.md +100 -0
- package/dist/compliance-off/skills/git/references/tracker/github/ensure-traceable-issue.md +74 -0
- package/dist/compliance-off/skills/git/references/tracker/github/fetch-issue.md +69 -0
- package/dist/compliance-off/skills/git/references/tracker/github/fetch-issues-batch.md +65 -0
- package/dist/compliance-off/skills/git/references/tracker/github/gather-release-evidence.md +48 -0
- package/dist/compliance-off/skills/git/references/tracker/github/setup-task.md +77 -0
- package/dist/compliance-off/skills/git/references/tracker/jira/create-release.md +35 -0
- package/dist/compliance-off/skills/git/references/tracker/jira/ensure-pr-ready.md +100 -0
- package/dist/compliance-off/skills/git/references/tracker/jira/ensure-traceable-issue.md +61 -0
- package/dist/compliance-off/skills/git/references/tracker/jira/fetch-issue.md +51 -0
- package/dist/compliance-off/skills/git/references/tracker/jira/fetch-issues-batch.md +63 -0
- package/dist/compliance-off/skills/git/references/tracker/jira/gather-release-evidence.md +47 -0
- package/dist/compliance-off/skills/git/references/tracker/jira/setup-task.md +82 -0
- package/dist/compliance-off/skills/git/references/tracker/linear/create-release.md +35 -0
- package/dist/compliance-off/skills/git/references/tracker/linear/ensure-pr-ready.md +100 -0
- package/dist/compliance-off/skills/git/references/tracker/linear/ensure-traceable-issue.md +61 -0
- package/dist/compliance-off/skills/git/references/tracker/linear/fetch-issue.md +51 -0
- package/dist/compliance-off/skills/git/references/tracker/linear/fetch-issues-batch.md +63 -0
- package/dist/compliance-off/skills/git/references/tracker/linear/gather-release-evidence.md +47 -0
- package/dist/compliance-off/skills/git/references/tracker/linear/setup-task.md +83 -0
- package/dist/compliance-off/skills/git/references/trust-rule.md +7 -0
- package/dist/core/agent-models.js +19 -4
- package/dist/core/assets.js +126 -17
- package/dist/core/compliance-off-files.js +27 -0
- package/dist/core/curation-variants.js +460 -112
- package/dist/core/flags.js +2 -2
- package/dist/core/installed-variants.js +63 -0
- package/dist/core/manifest.js +48 -5
- package/dist/core/mds-variants.js +700 -3
- package/dist/core/orphan-sweep.js +11 -2
- package/dist/core/plugins.js +65 -8
- package/dist/curation-compliance-off/agents/triage.md +176 -0
- package/dist/curation-compliance-off/commands/bug-analysis.md +349 -0
- package/dist/curation-compliance-off/commands/code-review.md +481 -0
- package/dist/curation-compliance-off/commands/dynamic-build.md +1211 -0
- package/dist/curation-compliance-off/commands/dynamic-tickets.md +634 -0
- package/dist/curation-compliance-off/commands/implement.md +689 -0
- package/dist/curation-compliance-off/commands/plan.md +631 -0
- package/dist/curation-compliance-off/commands/release.md +279 -0
- package/dist/curation-compliance-off/commands/resolve.md +692 -0
- package/dist/curation-off/agents/code.md +6 -6
- package/dist/curation-off/agents/fix.md +6 -6
- package/dist/curation-off/agents/harden.md +7 -6
- package/dist/curation-off/agents/refactor.md +6 -6
- package/dist/curation-off/commands/bug-analysis.md +69 -119
- package/dist/curation-off/commands/dynamic-build.md +23 -23
- package/dist/curation-off/commands/implement.md +46 -32
- package/dist/curation-off/commands/release.md +1 -1
- package/dist/curation-off/commands/resolve.md +35 -31
- package/dist/curation-off/commands/self-review.md +8 -7
- package/dist/skills/git/references/pr/resolve-review-threads.md +1 -1
- package/dist/targets/claude-code/behavior-install.js +23 -9
- package/dist/targets/claude-code/charter-render.js +374 -0
- package/dist/targets/claude-code/compliance-install.js +32 -12
- package/dist/targets/claude-code/compliance-off-files.js +245 -0
- package/dist/targets/claude-code/curation-install.js +570 -100
- package/dist/targets/claude-code/installer.js +467 -62
- package/dist/targets/claude-code/language-stamp.js +6 -0
- package/dist/targets/claude-code/linked-folder.js +182 -0
- package/dist/targets/claude-code/reference-converge.js +118 -0
- package/dist/targets/claude-code/tracker-install.js +21 -8
- package/dist/targets/claude-code/tracker-servers.js +20 -6
- package/dist/targets/claude-code/workflow-folder-install.js +231 -0
- package/dist/variant-axes.json +109 -0
- package/package.json +1 -1
- package/src/assets/agents/_partials/_code.mds +6 -6
- package/src/assets/agents/evaluate.md +1 -1
- package/src/assets/agents/git.mds +32 -0
- package/src/assets/agents/harden.mds +7 -6
- package/src/assets/agents/test.md +21 -12
- package/src/assets/agents/triage.mds +2 -0
- package/src/assets/agents/validate.md +10 -10
- package/src/assets/commands/_partials/_compliance.mds +5 -3
- package/src/assets/commands/_partials/_engine.mds +9 -8
- package/src/assets/commands/_partials/_publication.mds +10 -1
- package/src/assets/commands/bug-analysis.mds +80 -126
- package/src/assets/commands/code-review.mds +43 -0
- package/src/assets/commands/dynamic-build.mds +109 -15
- package/src/assets/commands/dynamic-tickets.mds +13 -0
- package/src/assets/commands/implement.mds +145 -33
- package/src/assets/commands/plan.mds +19 -0
- package/src/assets/commands/release.mds +50 -1
- package/src/assets/commands/resolve.mds +217 -32
- package/src/assets/commands/self-review.mds +8 -7
- package/src/assets/mds/git/_ops.mds +23 -0
- package/src/assets/mds/git/_ops_steps.mds +17 -0
- package/src/assets/mds/git/_pr.mds +1 -1
- package/src/assets/mds/git/_references.mds +6 -0
- package/src/assets/mds/tracker/_common.mds +4 -0
- package/src/assets/mds/tracker/_github.mds +42 -0
- package/src/assets/mds/tracker/_jira.mds +43 -0
- package/src/assets/mds/tracker/_linear.mds +43 -0
- package/src/assets/rules/quality.md +2 -0
- package/src/assets/scripts/ci-wait.cjs +204 -126
- package/src/assets/scripts/hooks/assets/implement-installed +1 -0
- package/src/assets/scripts/hooks/assets/orchestrator-charter.md +13 -11
- package/src/assets/scripts/hooks/preamble +18 -8
- package/src/assets/scripts/hooks/session-start-orchestrator +4 -2
- package/src/assets/scripts/pr-evidence.cjs +41 -2
- package/src/assets/scripts/verify-evidence.cjs +408 -56
- package/src/assets/skills/agent-references/references/commands/implement-revalidate.md +3 -3
- package/src/assets/skills/agent-references/references/commands/plan-levels.md +1 -1
- package/src/assets/skills/agent-references/references/synthesize/bug-analysis.md +6 -2
- package/src/assets/skills/agent-references/references/validate/passed-alone.md +7 -7
- package/src/assets/skills/docs-framework/SKILL.md +5 -2
- package/src/assets/skills/git/SKILL.md +3 -3
- package/src/assets/skills/git/references/github-api.md +2 -139
- package/src/assets/skills/git/references/github-posting.md +158 -0
- package/src/assets/skills/review-methodology/SKILL.md +1 -1
- package/src/assets/skills/review-methodology/references/patterns.md +1 -1
- package/src/assets/skills/review-methodology/references/report-template.md +1 -2
- package/src/assets/skills/testing/SKILL.md +2 -4
|
@@ -36,7 +36,7 @@ Run the commands of package.json, Makefile, Cargo.toml or similar in this order,
|
|
|
36
36
|
| 3 | Lint | `cargo clippy`, `make lint` | none |
|
|
37
37
|
| 4 | Test | `npm test`, `make test` | `vitest run --reporter=dot`, `jest --silent`, `pytest -q`, `cargo test -q`, `go test` without `-v`, `gradle -q test`, `mvn -q test` |
|
|
38
38
|
|
|
39
|
-
Use the quiet form where the project's command runs that tool. After a failed Test row, re-run each of its first 20 failed test files alone, once, verbose,
|
|
39
|
+
Use the quiet form where the project's command runs that tool. After a failed Test row, re-run each of its first 20 failed test files alone, once, verbose, never the suite: this is the one exception to the never-re-run rule under Running commands. First, run `d="${CLAUDE_CONFIG_DIR:-}"; case "$d" in /*) ;; *) d="$HOME/.claude" ;; esac; printf '%s\n' "$d/skills/devflow:agent-references/references/validate/passed-alone.md"` and Read it; re-run only a path it accepts (none if unread). PASSED-ALONE needs all of: a BASE_SHA; a checked, tracked path; a FILES_CHANGED that omits it; a test timeout, spawn or resource error; a re-run adding only that file, no name filter; `EXIT=0`; its tests ran and passed. Else REAL; a re-run is never BLOCKED. PASS needs PASSED-ALONE files to explain every failure; the Test row then counts as passed, also for Lint pack, in any output form. Never name labels in Failures, Parsed References or `details`.
|
|
40
40
|
|
|
41
41
|
**Gate ownership:** Run the full suite once per HEAD. You are the only agent that does.
|
|
42
42
|
|
|
@@ -44,20 +44,20 @@ Use the quiet form where the project's command runs that tool. After a failed Te
|
|
|
44
44
|
|
|
45
45
|
Run builds, typechecks, lints and tests in the foreground, each with an explicit Bash `timeout` above its expected run time. The ceiling is 600000 ms, or `BASH_MAX_TIMEOUT_MS` when set (`echo ${BASH_MAX_TIMEOUT_MS:-600000}`).
|
|
46
46
|
|
|
47
|
-
- Capture, then tail, in one Bash call
|
|
48
|
-
- Never background a
|
|
49
|
-
- Prefer the scoped command for the change
|
|
50
|
-
- A run
|
|
51
|
-
- A run expected to exceed the ceiling
|
|
47
|
+
- Capture, then tail, in one Bash call: `LOG=$(mktemp); echo "LOG=$LOG"; <command> >"$LOG" 2>&1; rc=$?; tail -n 40 "$LOG"; printf '\nEXIT=%s\n' "$rc"`. The last `EXIT=` line is the result; never decide one from a grep count.
|
|
48
|
+
- Never background a build or test, and never poll across turns: no `sleep` or `true` turns, no sentinel-file checks, no Monitor.
|
|
49
|
+
- Prefer the scoped command for the change; for the whole set, one workspace command over per-package loops.
|
|
50
|
+
- A run past its timeout moves to the background: no tool call, even a Read, until its end notice, then Read the last `EXIT=` line of the file the move names, not `$LOG`; it alone sets the label, not the notice. With none read it is BLOCKED: report its duration and log path. Report only after the end notice.
|
|
51
|
+
- A run expected to exceed the ceiling may be split into parts, run in sequence.
|
|
52
52
|
- Never re-run a command when nothing it reads has changed.
|
|
53
|
-
- Never wrap a build or test command in `sh -c`, `bash -c`, `python3 -c` or `node -e`: permission rules deny wrapped commands they
|
|
53
|
+
- Never wrap a build or test command in `sh -c`, `bash -c`, `python3 -c` or `node -e`: permission rules deny wrapped commands they allow directly.
|
|
54
54
|
- The same rules hold inside a dynamic Workflow sub-agent.
|
|
55
55
|
|
|
56
56
|
## Lint pack
|
|
57
57
|
|
|
58
58
|
Only if the first `GATE_LEVEL:` line is exactly `lean`, run it last, once the table commands that exist pass; else never run it or print anything about it. The Lint row never runs it. Use the root `package.json` script `lint-pack`, else the root `Makefile` target; look nowhere else. Neither: not configured.
|
|
59
59
|
|
|
60
|
-
A first `BASE_SHA:` not matching `^[0-9a-f]{40}$` is an error; else run `npm run -s lint-pack -- <BASE_SHA>` or `make -s lint-pack BASE=<BASE_SHA>` in the capture form with an explicit Bash `timeout`; Read the log. Its last `LINT_PACK:` line decides: `no-config` is not configured, `clean` is clean, `matches <n>` sets FAIL, each record into Parsed References. Any other line
|
|
60
|
+
A first `BASE_SHA:` not matching `^[0-9a-f]{40}$` is an error; else run `npm run -s lint-pack -- <BASE_SHA>` or `make -s lint-pack BASE=<BASE_SHA>` in the capture form with an explicit Bash `timeout`; past it, wait for its end notice, then Read the log. Its last `LINT_PACK:` line decides: `no-config` is not configured, `clean` is clean, `matches <n>` sets FAIL, each record into Parsed References. Any other line or none is an error: Status stays; the pack is UNVERIFIED, never a pass. `EXIT=` never decides it; an error is never BLOCKED. Copy the `pack-changed` paths and `skipped-binary` count to the `Lint pack:` line.
|
|
61
61
|
|
|
62
62
|
## Output
|
|
63
63
|
|
|
@@ -72,7 +72,7 @@ HEAD: {`git rev-parse HEAD`, read before the first command}
|
|
|
72
72
|
| Command | Status | Exit | Duration |
|
|
73
73
|
|---|---|---|---|
|
|
74
74
|
|
|
75
|
-
Passed alone: {paths, if any}; bound 20 files
|
|
75
|
+
Passed alone: {paths, if any}; bound 20 files
|
|
76
76
|
|
|
77
77
|
### Failures (if FAIL)
|
|
78
78
|
|
|
@@ -98,4 +98,4 @@ Report cap: final message at most about 1,500 tokens; longer material goes to a
|
|
|
98
98
|
|
|
99
99
|
## Boundaries
|
|
100
100
|
|
|
101
|
-
BLOCKED: no validation command found, a table command that cannot start, or missing dependencies.
|
|
101
|
+
BLOCKED: no validation command found, a table command that cannot start or with no `EXIT=` line read, or missing dependencies.
|
|
@@ -7,9 +7,11 @@ D-COMPLIANCE-INJECT: the compliance instruction reaches an agent only through a
|
|
|
7
7
|
prompt, and only when the resolved lens is on. No Code, Fix, Review or Design body names
|
|
8
8
|
the compliance skill, so a lens-off spawn pays nothing for it. `compliance_directive()` is the
|
|
9
9
|
one home of the directive text; `compliance_inject()` is how a pass-through host sets it.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
No install-time variant carries the lens: it is the union of the machine, the default
|
|
11
|
+
branch and the worktree (D-LENS-UNION), so a repository can turn it on when the machine
|
|
12
|
+
switch is off. The posting steps are the opposite case. They are an install-time variant
|
|
13
|
+
keyed on the machine switch alone, as compliance arms in each host, and a repository key
|
|
14
|
+
cannot restore one.
|
|
13
15
|
|
|
14
16
|
@define compliance_frameworks():
|
|
15
17
|
`COMPLIANCE_FRAMEWORKS` is the settings line's `COMPLIANCE` with `generic` written `none`: `off`, `none`, or the framework ids the machine and this repository declare.
|
|
@@ -36,6 +36,7 @@ Gate 2 inputs are produced by `/devflow:dynamic-plan`'s plan-challenge step —
|
|
|
36
36
|
**Test agent** (only if acceptance criteria or a test plan exist):
|
|
37
37
|
- Scenario-based acceptance tests covering functionality, API contracts, performance
|
|
38
38
|
- FAIL → fix-and-continue — a Fix agent applies the demanded fixes and self-verifies its own build. The recorded verdict becomes `FAIL-FIXED`; Gate 2 then proceeds. In SINGLE mode the run reports it as `UNVERIFIED`, never PASS.
|
|
39
|
+
- BLOCKED (no result), or any other or missing verdict → no fix, and the run never reports PASS.
|
|
39
40
|
|
|
40
41
|
**When Gate 2 inputs are absent:**
|
|
41
42
|
- No plan → skip the Evaluate agent silently (note in output: "Gate 2 Evaluate agent skipped — no plan available")
|
|
@@ -142,17 +143,17 @@ This applies to both: multiple Code agents working on a single ticket AND multi-
|
|
|
142
143
|
@define build_execution_doctrine():
|
|
143
144
|
### Build execution doctrine — the Running commands block (LOAD-BEARING)
|
|
144
145
|
|
|
145
|
-
The
|
|
146
|
+
The Code, Fix, Refactor, Validate and Test agents each carry this `## Running commands` block in their bodies, so each prompt in this engine names the block ("your Running commands block") instead of copying it:
|
|
146
147
|
|
|
147
148
|
Run builds, typechecks, lints and tests in the foreground, each with an explicit Bash `timeout` above its expected run time. The ceiling is 600000 ms, or `BASH_MAX_TIMEOUT_MS` when set (`echo ${BASH_MAX_TIMEOUT_MS:-600000}`).
|
|
148
149
|
|
|
149
|
-
- Capture, then tail, in one Bash call
|
|
150
|
-
- Never background a
|
|
151
|
-
- Prefer the scoped command for the change
|
|
152
|
-
- A run
|
|
153
|
-
- A run expected to exceed the ceiling
|
|
150
|
+
- Capture, then tail, in one Bash call: `LOG=$(mktemp); echo "LOG=$LOG"; <command> >"$LOG" 2>&1; rc=$?; tail -n 40 "$LOG"; printf '\nEXIT=%s\n' "$rc"`. The last `EXIT=` line is the result; never decide one from a grep count.
|
|
151
|
+
- Never background a build or test, and never poll across turns: no `sleep` or `true` turns, no sentinel-file checks, no Monitor.
|
|
152
|
+
- Prefer the scoped command for the change; for the whole set, one workspace command over per-package loops.
|
|
153
|
+
- A run past its timeout moves to the background: no tool call, even a Read, until its end notice, then Read the last `EXIT=` line of the file the move names, not `$LOG`; it alone sets the label, not the notice. With none read it is BLOCKED: report its duration and log path. Report only after the end notice.
|
|
154
|
+
- A run expected to exceed the ceiling may be split into parts, run in sequence.
|
|
154
155
|
- Never re-run a command when nothing it reads has changed.
|
|
155
|
-
- Never wrap a build or test command in `sh -c`, `bash -c`, `python3 -c` or `node -e`: permission rules deny wrapped commands they
|
|
156
|
+
- Never wrap a build or test command in `sh -c`, `bash -c`, `python3 -c` or `node -e`: permission rules deny wrapped commands they allow directly.
|
|
156
157
|
- The same rules hold inside a dynamic Workflow sub-agent.
|
|
157
158
|
|
|
158
159
|
**Cheapest-sufficient validation:** iterate with the fastest check that proves the change — `tsc --noEmit`, `cargo check`, `go vet`, a single test file — the ecosystem's cheapest sufficient signal. Reserve expensive full/optimized builds and whole-suite runs for the final gates only.
|
|
@@ -205,7 +206,7 @@ Each ticket engine run returns a structured result. The Synthesize agent or the
|
|
|
205
206
|
],
|
|
206
207
|
"gate2": {
|
|
207
208
|
"evaluateVerdict": "PASS | FAIL | FAIL-FIXED | SKIPPED",
|
|
208
|
-
"testVerdict": "PASS | FAIL | FAIL-FIXED | SKIPPED",
|
|
209
|
+
"testVerdict": "PASS | FAIL | FAIL-FIXED | SKIPPED | BLOCKED",
|
|
209
210
|
"skipReasons": ["string — why a gate was skipped, if applicable"]
|
|
210
211
|
}
|
|
211
212
|
}
|
|
@@ -3,12 +3,21 @@ A partial: the publication-value gate. D-SETTINGS-LINE: it imports nothing from
|
|
|
3
3
|
its consumers, and this text takes `REVIEW_PUBLICATION` from the line resolved
|
|
4
4
|
there for the worktree's root.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
`publication_resolve` is the two resolution steps alone. `publication_gate` is those steps plus the
|
|
7
|
+
note that names the Git agent's publication gate; a host with compliance off calls only the steps,
|
|
8
|
+
because the gate's reference file is not installed there.
|
|
9
|
+
|
|
10
|
+
@define publication_resolve():
|
|
7
11
|
**Resolve `REVIEW_PUBLICATION` per worktree:** take `REVIEW_PUBLICATION` from that worktree's settings line — the line resolved above for `{root}`, the worktree's root, by the settings block when this run has not yet resolved that root; multi-worktree repos may resolve different values per worktree. The line already caps the personal choice at the team's (D-PUBLICATION-CEILING), so it is `off`, `auto` or `full`, and `off` when the line was unresolvable.
|
|
8
12
|
|
|
9
13
|
**Evidence stub:** only when `EVIDENCE_POLICY` is `required`, a resolved `off` becomes `stub`, so a counts-only record still reaches the PR. `stub` is never a config value: the settings line never carries it.
|
|
14
|
+
@end
|
|
15
|
+
|
|
16
|
+
@define publication_gate():
|
|
17
|
+
{{publication_resolve()}}
|
|
10
18
|
|
|
11
19
|
Note: `auto` is NOT fail-open — under `auto`, the Git agent probes the repository visibility and treats any error or unrecognised value as PUBLIC (mode STUB). What each value does is decided by the Git agent's publication gate (`references/publication-gate.md` step 2); this partial only resolves the value.
|
|
12
20
|
@end
|
|
13
21
|
|
|
22
|
+
@export publication_resolve
|
|
14
23
|
@export publication_gate
|
|
@@ -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
|
|
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`;
|
|
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
|
-
|
|
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
|
-
|
|
103
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
125
|
-
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
148
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
193
|
-
4.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
{
|
|
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}/{
|
|
296
|
-
- Static findings: {ANALYSIS_DIR}/static-findings.md (if
|
|
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
|
-
|
|
|
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
|
-
|
|
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** —
|
|
354
|
-
2. **
|
|
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
|
|
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.
|