devflow-kit 3.3.0 → 3.4.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 +18 -0
- package/dist/agents/code.md +330 -0
- package/{src/assets → dist}/agents/design.md +1 -1
- package/{src/assets → dist}/agents/diagnose.md +1 -2
- package/dist/agents/git.md +29 -56
- package/{src/assets → dist}/agents/knowledge.md +4 -3
- package/{src/assets → dist}/agents/research.md +2 -2
- package/{src/assets → dist}/agents/review.md +8 -7
- package/{src/assets → dist}/agents/scrutinize.md +1 -1
- package/dist/agents/skim.md +148 -0
- package/{src/assets → dist}/agents/triage.md +1 -1
- package/dist/cli/commands/init.js +62 -0
- package/dist/cli/commands/learning.js +38 -3
- package/dist/cli/commands/uninstall.js +42 -1
- package/dist/commands/bug-analysis.md +30 -8
- package/dist/commands/code-review.md +141 -60
- package/dist/commands/debug.md +14 -12
- package/dist/commands/dynamic-build.md +37 -38
- package/dist/commands/dynamic-plan.md +30 -18
- package/dist/commands/dynamic-profile.md +27 -13
- package/dist/commands/dynamic-tickets.md +28 -14
- package/dist/commands/explore.md +15 -13
- package/dist/commands/implement.md +33 -28
- package/dist/commands/plan.md +37 -24
- package/dist/commands/release.md +69 -4
- package/dist/commands/research.md +33 -11
- package/dist/commands/resolve.md +35 -32
- package/dist/commands/self-review.md +36 -23
- package/dist/core/agent-models.js +43 -0
- package/dist/core/assets.js +55 -10
- package/dist/core/claude-md-audit.js +190 -0
- package/dist/core/feature-switch.js +20 -1
- package/dist/core/flags.js +28 -0
- package/dist/core/fs-atomic.js +8 -3
- package/dist/core/learning-variants.js +213 -0
- package/dist/core/manifest.js +62 -0
- package/dist/core/mds-variants.js +38 -1
- package/dist/core/plugins.js +71 -9
- package/{src/assets → dist/learning-off}/agents/code.md +6 -10
- package/dist/learning-off/agents/design.md +119 -0
- package/dist/learning-off/agents/diagnose.md +210 -0
- package/dist/learning-off/agents/knowledge.md +90 -0
- package/dist/learning-off/agents/research.md +149 -0
- package/dist/learning-off/agents/review.md +228 -0
- package/dist/learning-off/agents/scrutinize.md +117 -0
- package/{src/assets → dist/learning-off}/agents/skim.md +1 -8
- package/dist/learning-off/agents/triage.md +163 -0
- package/dist/learning-off/commands/bug-analysis.md +420 -0
- package/dist/learning-off/commands/code-review.md +525 -0
- package/dist/learning-off/commands/debug.md +294 -0
- package/dist/learning-off/commands/dynamic-build.md +1255 -0
- package/dist/learning-off/commands/dynamic-plan.md +424 -0
- package/dist/learning-off/commands/dynamic-profile.md +214 -0
- package/dist/learning-off/commands/dynamic-tickets.md +632 -0
- package/dist/learning-off/commands/explore.md +210 -0
- package/dist/learning-off/commands/implement.md +808 -0
- package/dist/learning-off/commands/plan.md +664 -0
- package/dist/learning-off/commands/release.md +310 -0
- package/dist/learning-off/commands/research.md +222 -0
- package/dist/learning-off/commands/resolve.md +837 -0
- package/dist/learning-off/commands/self-review.md +266 -0
- package/dist/skills/git/references/tracker/_contract.md +33 -0
- package/dist/skills/git/references/tracker/github/fetch-issue.md +2 -0
- package/dist/skills/git/references/tracker/github/fetch-issues-batch.md +2 -0
- package/dist/skills/git/references/tracker/github/gather-release-evidence.md +4 -0
- package/dist/skills/git/references/tracker/github/post-wave-report.md +2 -0
- package/dist/skills/git/references/tracker/github/setup-task.md +12 -0
- package/dist/skills/git/references/tracker/jira/associate-release.md +1 -1
- package/dist/skills/git/references/tracker/jira/fetch-issue.md +2 -0
- package/dist/skills/git/references/tracker/jira/fetch-issues-batch.md +2 -0
- package/dist/skills/git/references/tracker/jira/gather-release-evidence.md +4 -0
- package/dist/skills/git/references/tracker/jira/post-wave-report.md +2 -0
- package/dist/skills/git/references/tracker/jira/setup-task.md +14 -2
- package/dist/skills/git/references/tracker/linear/associate-release.md +1 -1
- package/dist/skills/git/references/tracker/linear/fetch-issue.md +2 -0
- package/dist/skills/git/references/tracker/linear/fetch-issues-batch.md +2 -0
- package/dist/skills/git/references/tracker/linear/gather-release-evidence.md +4 -0
- package/dist/skills/git/references/tracker/linear/post-wave-report.md +2 -0
- package/dist/skills/git/references/tracker/linear/setup-task.md +14 -2
- package/dist/targets/claude-code/installer.js +72 -36
- package/dist/targets/claude-code/language-stamp.js +185 -0
- package/dist/targets/claude-code/learning-install.js +489 -0
- package/package.json +1 -1
- package/src/assets/agents/code.mds +339 -0
- package/src/assets/agents/design.mds +149 -0
- package/src/assets/agents/diagnose.mds +225 -0
- package/src/assets/agents/evaluate.md +1 -3
- package/src/assets/agents/git.mds +29 -56
- package/src/assets/agents/knowledge.mds +125 -0
- package/src/assets/agents/research.mds +176 -0
- package/src/assets/agents/review.mds +286 -0
- package/src/assets/agents/scrutinize.mds +132 -0
- package/src/assets/agents/skim.mds +161 -0
- package/src/assets/agents/triage.mds +194 -0
- package/src/assets/agents/validate.md +8 -6
- package/src/assets/commands/_partials/_compliance.mds +5 -4
- package/src/assets/commands/_partials/_decisions.mds +31 -0
- package/src/assets/commands/_partials/_engine.mds +9 -1
- package/src/assets/commands/_partials/_knowledge.mds +25 -12
- package/src/assets/commands/_partials/_preamble.mds +33 -9
- package/src/assets/commands/_partials/_publication.mds +5 -4
- package/src/assets/commands/_partials/_settings.mds +13 -5
- package/src/assets/commands/_partials/_wave.mds +8 -0
- package/src/assets/commands/bug-analysis.mds +24 -2
- package/src/assets/commands/code-review.mds +147 -44
- package/src/assets/commands/debug.mds +17 -1
- package/src/assets/commands/dynamic-build.mds +33 -2
- package/src/assets/commands/dynamic-plan.mds +36 -6
- package/src/assets/commands/dynamic-profile.mds +9 -1
- package/src/assets/commands/dynamic-tickets.mds +16 -2
- package/src/assets/commands/explore.mds +27 -1
- package/src/assets/commands/implement.mds +41 -8
- package/src/assets/commands/plan.mds +47 -8
- package/src/assets/commands/{release.md → release.mds} +27 -24
- package/src/assets/commands/research.mds +28 -4
- package/src/assets/commands/resolve.mds +43 -2
- package/src/assets/commands/self-review.mds +30 -5
- package/src/assets/mds/tracker/_contract.mds +72 -0
- package/src/assets/mds/tracker/_github.mds +13 -2
- package/src/assets/mds/tracker/_jira.mds +17 -5
- package/src/assets/mds/tracker/_linear.mds +17 -5
- package/src/assets/mds/tracker/_mcp.mds +2 -2
- package/src/assets/mds/tracker/_steps.mds +97 -0
- package/src/assets/rules/context-economy.md +10 -0
- package/src/assets/rules/go.md +1 -0
- package/src/assets/rules/java.md +1 -0
- package/src/assets/rules/python.md +1 -0
- package/src/assets/rules/rust.md +1 -0
- package/src/assets/rules/typescript.md +1 -0
- package/src/assets/scripts/claude-md-audit.cjs +611 -0
- package/src/assets/scripts/hooks/assets/orchestrator-charter.md +1 -2
- package/src/assets/scripts/hooks/json-helper.cjs +13 -5
- package/src/assets/scripts/hooks/json-parse +34 -10
- package/src/assets/scripts/hooks/session-start-context +315 -7
- package/src/assets/skills/apply-decisions/SKILL.md +1 -1
- package/src/assets/skills/apply-feature-knowledge/SKILL.md +5 -5
- package/src/assets/skills/feature-knowledge/SKILL.md +43 -12
- package/src/assets/skills/quality-gates/SKILL.md +1 -1
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Comprehensive branch review using specialized sub-agents for PR readiness
|
|
3
|
+
---
|
|
4
|
+
# Code Review Command
|
|
5
|
+
|
|
6
|
+
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.
|
|
7
|
+
|
|
8
|
+
## Usage
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
/code-review (review current branch — or all worktrees if multiple found)
|
|
12
|
+
/code-review #42 (review specific PR)
|
|
13
|
+
/code-review --full (force full-branch review, ignore previous review state)
|
|
14
|
+
/code-review --path /path/to/worktree (review a specific worktree only)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Phases
|
|
18
|
+
|
|
19
|
+
### Phase 0: Worktree Discovery & Pre-Flight
|
|
20
|
+
|
|
21
|
+
#### Step 0a: Discover Worktrees
|
|
22
|
+
|
|
23
|
+
**Produces:** WORKTREES
|
|
24
|
+
|
|
25
|
+
1. **Discover reviewable worktrees** using the `devflow:worktree-support` skill discovery algorithm:
|
|
26
|
+
- Run `git worktree list --porcelain` → parse, filter (skip protected/detached/mid-rebase), dedup by branch, sort by recent commit
|
|
27
|
+
- 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
|
|
28
|
+
2. **If `--path` flag provided:** use only that worktree, skip discovery
|
|
29
|
+
**`--path` validation**: Before proceeding, verify the path exists as a directory and appears in `git worktree list` output. If not: report error and stop.
|
|
30
|
+
3. **If only 1 reviewable worktree** (the common case): proceed as single-worktree flow — zero behavior change
|
|
31
|
+
4. **If multiple reviewable worktrees:** report "Found N worktrees with reviewable branches: {list with paths and branches}" and proceed with multi-worktree flow
|
|
32
|
+
|
|
33
|
+
#### Step 0b: Resolve the compliance lens
|
|
34
|
+
|
|
35
|
+
**Produces:** COMPLIANCE_ACTIVE, COMPLIANCE_FRAMEWORKS
|
|
36
|
+
|
|
37
|
+
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root when the run has one worktree:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> LEARNING=<on|off> KNOWLEDGE=<on|off>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=on LEARNING=on KNOWLEDGE=off` instead.
|
|
44
|
+
|
|
45
|
+
The accepted line is the only source of these values: the script alone folds the committed `.devflow/project.json`, the personal `.devflow/config.json` and the machine manifest.
|
|
46
|
+
|
|
47
|
+
**Resolve the compliance lens** for each worktree root, from its settings line — the line resolved above for that root, by the settings block when this run has not yet resolved it (every framework reference is installed on every machine, so no file check decides it).
|
|
48
|
+
|
|
49
|
+
**Set the compliance lens** from that line: `COMPLIANCE_FRAMEWORKS` is the settings line's `COMPLIANCE` with `generic` written `none`: `off`, `none`, or the framework ids the machine and this repository declare.
|
|
50
|
+
|
|
51
|
+
`COMPLIANCE_ACTIVE` is `true` unless `COMPLIANCE_FRAMEWORKS` is `off`.
|
|
52
|
+
Keep each worktree's values for every downstream phase of that worktree.
|
|
53
|
+
|
|
54
|
+
#### Step 0b-ii: Resolve the evidence policy
|
|
55
|
+
|
|
56
|
+
**Produces:** EVIDENCE_POLICY, ISSUE_REQUIRED, APPLY_CONVENTIONS, REQUIRE_NON_AUTHOR_APPROVAL
|
|
57
|
+
|
|
58
|
+
**Resolve the evidence policy once per run**, from the repository root, before any step reads the values:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
node "$HOME/.devflow/scripts/resolve-evidence-policy.cjs" 2>/dev/null; echo "exit=$?"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `EVIDENCE_POLICY=<required|standard> SOURCE=<file|worktree|default|invalid|error> REF=<branch|none>[ WARN=<remote-unavailable|invalid-file|raised-by-compliance|pr-changes-policy>[,…]] ISSUE_REQUIRED=<true|false> APPLY_CONVENTIONS=<true|false> REQUIRE_NON_AUTHOR_APPROVAL=<true|false>` — these fields, in this order, nothing else, where `<branch>` is a branch name such as `main`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `EVIDENCE_POLICY=required SOURCE=error REF=none ISSUE_REQUIRED=true APPLY_CONVENTIONS=true REQUIRE_NON_AUTHOR_APPROVAL=true` instead.
|
|
65
|
+
|
|
66
|
+
Set `EVIDENCE_POLICY`, `ISSUE_REQUIRED`, `APPLY_CONVENTIONS` and `REQUIRE_NON_AUTHOR_APPROVAL` from the accepted line. Pass agents only the three mechanism inputs, never `EVIDENCE_POLICY`. Report `Evidence policy: {EVIDENCE_POLICY} (source: {SOURCE})`, plus any `WARN` tokens as advisory, once in the final report.
|
|
67
|
+
|
|
68
|
+
#### Step 0c: Per-Worktree Pre-Flight (Git Agent)
|
|
69
|
+
|
|
70
|
+
**Produces:** BRANCH_INFO, PR_INFO, PR_DESCRIPTION, PR_DESCRIPTION_GUIDANCE
|
|
71
|
+
**Requires:** WORKTREES
|
|
72
|
+
|
|
73
|
+
Discover PR description guidance from plan artifact (per worktree):
|
|
74
|
+
1. List `{worktree}/.devflow/docs/design/*.md` files
|
|
75
|
+
2. Sort by timestamp in filename (descending -- timestamps are YYYY-MM-DD_HHMM, naturally sortable)
|
|
76
|
+
3. Read the most recent file, extract `## PR Description Guidance` section
|
|
77
|
+
4. If no plan files exist or section not found, set `PR_DESCRIPTION_GUIDANCE` to `(none)`
|
|
78
|
+
|
|
79
|
+
Render the test-plan block (per worktree) from `/implement`'s evidence file, and from nothing else:
|
|
80
|
+
1. `branch_slug` is `git -C "{worktree}" branch --show-current` with every `/` replaced by `-`.
|
|
81
|
+
2. Only when `branch_slug` matches `^[A-Za-z0-9._-]{1,200}$` and the file exists, run (the path double-quoted):
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
node "$HOME/.devflow/scripts/verify-evidence.cjs" render --plan "{worktree}/.devflow/docs/evidence-{branch_slug}.md"; echo "exit=$?"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
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.
|
|
88
|
+
|
|
89
|
+
For each reviewable worktree, spawn Git agent:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
Agent(subagent_type="Git", run_in_background=false):
|
|
93
|
+
"OPERATION: ensure-pr-ready
|
|
94
|
+
WORKTREE_PATH: {worktree_path} (omit if cwd)
|
|
95
|
+
PR_DESCRIPTION_GUIDANCE: {pr_description_guidance}
|
|
96
|
+
PR_TEST_PLAN_BLOCK: {PR_TEST_PLAN_BLOCK verbatim, or (none)}
|
|
97
|
+
APPLY_CONVENTIONS: {APPLY_CONVENTIONS}
|
|
98
|
+
Validate branch, commit if needed, push, create PR if needed.
|
|
99
|
+
Return: branch, base_branch, branch-slug, PR#"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
In multi-worktree mode, spawn all pre-flight agents **in a single message** (parallel).
|
|
103
|
+
|
|
104
|
+
**If BLOCKED:** In single-worktree mode, stop and report. In multi-worktree mode, report the failure but continue with other worktrees.
|
|
105
|
+
|
|
106
|
+
**Extract from response:** `branch`, `base_branch`, `branch_slug`, `pr_number` per worktree.
|
|
107
|
+
|
|
108
|
+
**Fetch PR body** (after extracting `pr_number`):
|
|
109
|
+
```bash
|
|
110
|
+
PR_DESCRIPTION=$(gh pr view {pr_number} --json body --jq '.body' 2>/dev/null || echo "(none)")
|
|
111
|
+
```
|
|
112
|
+
If `pr_number` is absent or the command fails, set `PR_DESCRIPTION` to `(none)`.
|
|
113
|
+
|
|
114
|
+
#### Step 0d: Incremental Detection & Timestamp Setup
|
|
115
|
+
|
|
116
|
+
**Produces:** DIFF_RANGE, REVIEW_DIR, TIMESTAMP
|
|
117
|
+
**Requires:** BRANCH_INFO
|
|
118
|
+
|
|
119
|
+
For each worktree:
|
|
120
|
+
|
|
121
|
+
1. Generate timestamp: `YYYY-MM-DD_HHMM`. If directory already exists (same-minute collision), append seconds (`YYYY-MM-DD_HHMMSS`).
|
|
122
|
+
2. Create timestamped review directory: `mkdir -p {worktree}/.devflow/docs/reviews/{branch-slug}/{timestamp}/`
|
|
123
|
+
3. Check if `{worktree}/.devflow/docs/reviews/{branch-slug}/.last-review-head` exists:
|
|
124
|
+
- **If yes AND `--full` NOT set:**
|
|
125
|
+
- Read the SHA from the file
|
|
126
|
+
- Verify reachable: `git -C {worktree} cat-file -t {sha}` (handles rebases — if unreachable, fallback to full)
|
|
127
|
+
- Check if SHA == current HEAD → if so, skip review: "No new commits since last review. Use --full for a full re-review."
|
|
128
|
+
- Set `DIFF_RANGE` to `{last-review-sha}...HEAD`
|
|
129
|
+
- **If no (first review), or `--full`:**
|
|
130
|
+
- Set `DIFF_RANGE` to `{base_branch}...HEAD`
|
|
131
|
+
|
|
132
|
+
#### Step 0e-i: Load Prior Resolution and Count Cycles
|
|
133
|
+
|
|
134
|
+
**Produces:** PRIOR_RESOLUTIONS, CYCLE_NUMBER
|
|
135
|
+
**Requires:** BRANCH_INFO
|
|
136
|
+
|
|
137
|
+
For each worktree, perform a single pass over timestamped directories:
|
|
138
|
+
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`
|
|
139
|
+
2. Iterate once: accumulate CYCLE_NUMBER count for each directory containing `resolution-summary.md`; capture the first (most-recent) such directory as PRIOR_DIR.
|
|
140
|
+
3. If CYCLE_NUMBER = 0: set PRIOR_RESOLUTIONS=(none), CYCLE_NUMBER=1, proceed.
|
|
141
|
+
4. Otherwise: set CYCLE_NUMBER = count + 1. Read `{PRIOR_DIR}/resolution-summary.md` as PRIOR_RESOLUTIONS.
|
|
142
|
+
5. If `--full`: still load PRIOR_RESOLUTIONS (valuable for Review agent cross-cycle awareness).
|
|
143
|
+
|
|
144
|
+
#### Step 0e-ii: Convergence Assessment
|
|
145
|
+
|
|
146
|
+
**Produces:** (refines CYCLE_NUMBER)
|
|
147
|
+
**Requires:** PRIOR_RESOLUTIONS, BRANCH_INFO
|
|
148
|
+
|
|
149
|
+
MAX_REVIEW_CYCLES = 10
|
|
150
|
+
|
|
151
|
+
1. If CYCLE_NUMBER > MAX_REVIEW_CYCLES:
|
|
152
|
+
Warn in output: "⚠️ Review pipeline has run {CYCLE_NUMBER-1} cycles (exceeds MAX_REVIEW_CYCLES=10). Consider merging or manual inspection."
|
|
153
|
+
Continue with review.
|
|
154
|
+
2. Parse Statistics table from PRIOR_RESOLUTIONS:
|
|
155
|
+
- Extract False Positive, Fixed, Deferred counts
|
|
156
|
+
- `deferred_count` = the Deferred row value (= FIX_SEPARATE + TECH_DEBT); By Design and Escalated are excluded from the fp_ratio denominator
|
|
157
|
+
- fp_ratio = fp_count / (fp_count + fixed_count + deferred_count)
|
|
158
|
+
- If denominator = 0: fp_ratio = 0, skip warning
|
|
159
|
+
- 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."
|
|
160
|
+
3. If fp_ratio > 0.7 AND CYCLE_NUMBER >= 3:
|
|
161
|
+
Warn in output: "⚠️ Convergence: {ratio}% false positives in cycle {N-1}. Consider merging or manual inspection."
|
|
162
|
+
Continue with review.
|
|
163
|
+
|
|
164
|
+
**Decision table — Step 0e-ii paths:**
|
|
165
|
+
|
|
166
|
+
| Condition | Outcome |
|
|
167
|
+
|-----------|---------|
|
|
168
|
+
| CYCLE_NUMBER > MAX_REVIEW_CYCLES | Warn in output, continue |
|
|
169
|
+
| denominator = 0 OR parsing failed | fp_ratio = 0, skip warning (degraded note on parse failure) |
|
|
170
|
+
| fp_ratio > 0.7 AND CYCLE_NUMBER >= 3 | Warn in output, continue |
|
|
171
|
+
|
|
172
|
+
#### Step 0f: Resolve Publication Mode (Per Worktree)
|
|
173
|
+
|
|
174
|
+
**Produces:** REVIEW_PUBLICATION
|
|
175
|
+
**Requires:** WORKTREES, EVIDENCE_POLICY
|
|
176
|
+
|
|
177
|
+
For each reviewable worktree, call:
|
|
178
|
+
|
|
179
|
+
**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.
|
|
180
|
+
|
|
181
|
+
**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.
|
|
182
|
+
|
|
183
|
+
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.
|
|
184
|
+
|
|
185
|
+
### Phase 1: Analyze Changed Files
|
|
186
|
+
|
|
187
|
+
**Produces:** REVIEW_FOCUS_LIST, DIFF_CLASS, DIFF_FILES
|
|
188
|
+
**Requires:** DIFF_RANGE, REVIEW_DIR, COMPLIANCE_ACTIVE (from Step 0b)
|
|
189
|
+
|
|
190
|
+
Per worktree, in order. Each `git` command here writes to a file and prints nothing.
|
|
191
|
+
|
|
192
|
+
#### Step 1.1: Classify the diff
|
|
193
|
+
|
|
194
|
+
**Produces:** DIFF_CLASS, CHANGED_PATHS, REVIEW_FOCUS_LIST (reduced classes)
|
|
195
|
+
**Requires:** DIFF_RANGE, REVIEW_DIR
|
|
196
|
+
|
|
197
|
+
List the changed paths into `{REVIEW_DIR}/paths.txt` and print only the line count (drop `-C "{WORKTREE_PATH}"` when there is no `WORKTREE_PATH`):
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
git -C "{WORKTREE_PATH}" diff --name-only --no-renames {DIFF_RANGE} > "{REVIEW_DIR}/paths.txt"
|
|
201
|
+
wc -l < "{REVIEW_DIR}/paths.txt"
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
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. `--no-renames` lists a moved file under its old path and its new one, so a move cannot take a file out of its own class.
|
|
205
|
+
|
|
206
|
+
Set `DIFF_CLASS` by these rules, in order; the first that decides wins:
|
|
207
|
+
|
|
208
|
+
1. **Instruction and config paths are `code`.** Any changed path that is `CLAUDE.md`, `AGENTS.md`, under `.claude/` or `src/assets/`, a `*.mds` file, under a plugin's `agents/`, `skills/` or `commands/` directory, `.devflow/project.json`, `.devflow/conventions.md`, or a manifest or build file (`package.json`, `go.mod`, `Cargo.toml`, `pyproject.toml`, `requirements*.txt`, `CMakeLists.txt`). This rule runs first, so a diff made only of such files is `code` and never `docs-only`.
|
|
209
|
+
2. **`docs-only`.** Every changed path matches `*.md`, `*.mdx`, `*.rst`, `*.txt`, `docs/**` or `CHANGELOG*`.
|
|
210
|
+
3. **`tests-only`.** Every changed path matches `tests/**`, `**/__tests__/**`, `*.test.*`, `*.spec.*`, `*_test.go`, `test_*.py` or `*_test.py`.
|
|
211
|
+
4. **`lockfile-only`.** Every changed path is `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`, `bun.lockb`, `Cargo.lock`, `go.sum`, `poetry.lock`, `uv.lock`, `Gemfile.lock` or `composer.lock`.
|
|
212
|
+
5. **Mixed non-code.** Every changed path matches the docs, tests or lockfile patterns, but no single rule above holds (docs with tests, tests with a lockfile): `DIFF_CLASS` names each class involved.
|
|
213
|
+
6. **Fail-safe is `code`.** A changed path that matches no class pattern makes the diff `code`, and so does an empty path list. A manifest change is `code` and never `lockfile-only`.
|
|
214
|
+
|
|
215
|
+
Each reduced class runs only its focus set, every member reading `diff.patch`:
|
|
216
|
+
|
|
217
|
+
- `docs-only`: documentation, consistency, security
|
|
218
|
+
- `tests-only`: testing, reliability, consistency, security
|
|
219
|
+
- `lockfile-only`: dependencies, security
|
|
220
|
+
|
|
221
|
+
A mixed non-code diff runs the union of the sets of the classes it holds. Language and conditional triggers inside a reduced class are suppressed: they add no focus, and Step 1.2 applies to the `code` class only.
|
|
222
|
+
|
|
223
|
+
#### Step 1.2: Choose the focuses
|
|
224
|
+
|
|
225
|
+
**Produces:** REVIEW_FOCUS_LIST (code class)
|
|
226
|
+
**Requires:** DIFF_CLASS, CHANGED_PATHS, COMPLIANCE_ACTIVE
|
|
227
|
+
|
|
228
|
+
When `DIFF_CLASS` is `code`, read the file types from the paths in `paths.txt` to determine conditional reviews:
|
|
229
|
+
|
|
230
|
+
| Condition | Adds Review |
|
|
231
|
+
|-----------|-------------|
|
|
232
|
+
| Any .ts or .tsx files | typescript |
|
|
233
|
+
| .tsx or .jsx files (React components) | react |
|
|
234
|
+
| .tsx or .jsx files (React components) | accessibility |
|
|
235
|
+
| .tsx/.jsx/.css/.scss files | ui-design |
|
|
236
|
+
| .go files | go |
|
|
237
|
+
| .java files | java |
|
|
238
|
+
| .py files | python |
|
|
239
|
+
| .rs files | rust |
|
|
240
|
+
| DB/migration files | database |
|
|
241
|
+
| Dependency files changed | dependencies |
|
|
242
|
+
| Docs or significant code | documentation |
|
|
243
|
+
| COMPLIANCE_ACTIVE AND diff touches regulated surface | compliance |
|
|
244
|
+
|
|
245
|
+
If `COMPLIANCE_ACTIVE` AND the diff touches regulated surface (data models, auth flows, logging/observability, payments, IaC, retention): add `compliance` to REVIEW_FOCUS_LIST for this worktree.
|
|
246
|
+
|
|
247
|
+
**Language focus stamp.** The eight language focuses — `typescript`, `react`, `accessibility`, `ui-design`, `go`, `java`, `python`, `rust` — ship with optional plugins, and the installer stamps the ones installed on this machine onto this line, rewriting it on every install and on `uninstall --plugin`:
|
|
248
|
+
|
|
249
|
+
Installed language focuses: (none)
|
|
250
|
+
|
|
251
|
+
A language focus is spawned only when its file-type condition above fires AND its name appears in that stamped line. A focus missing from the line is never spawned, even when its trigger fires. The eight core focuses are unconditional and are never stamp-gated.
|
|
252
|
+
|
|
253
|
+
#### Step 1.3: Write the diff files
|
|
254
|
+
|
|
255
|
+
**Produces:** DIFF_FILES
|
|
256
|
+
**Requires:** DIFF_RANGE, REVIEW_DIR, REVIEW_FOCUS_LIST
|
|
257
|
+
|
|
258
|
+
Write `diff.patch` once per worktree, by redirect:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
git -C "{WORKTREE_PATH}" diff --no-color --no-ext-diff --no-textconv {DIFF_RANGE} > "{REVIEW_DIR}/diff.patch"
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
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:
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
git -C "{WORKTREE_PATH}" diff --no-color --no-ext-diff --no-textconv {DIFF_RANGE} -- '<pathspec>' ... > "{REVIEW_DIR}/diff-{focus}.patch"
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
| Focus | Pathspecs |
|
|
271
|
+
|-------|-----------|
|
|
272
|
+
| typescript | `'*.ts' '*.tsx'` |
|
|
273
|
+
| react, accessibility | `'*.tsx' '*.jsx'` |
|
|
274
|
+
| ui-design | `'*.tsx' '*.jsx' '*.css' '*.scss'` |
|
|
275
|
+
| go | `'*.go'` |
|
|
276
|
+
| java | `'*.java'` |
|
|
277
|
+
| python | `'*.py'` |
|
|
278
|
+
| rust | `'*.rs'` |
|
|
279
|
+
|
|
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.
|
|
281
|
+
|
|
282
|
+
### Phase 1b: Load Context
|
|
283
|
+
|
|
284
|
+
**Produces:** FEATURE_KNOWLEDGE, FEATURE_KNOWLEDGE_RULES, COMPLIANCE_FRAMEWORKS (carried from Step 0b)
|
|
285
|
+
|
|
286
|
+
### Load Feature Knowledge
|
|
287
|
+
|
|
288
|
+
Resolve `{worktree}` as the checkout's toplevel, because feature knowledge bases are committed with the branch (D-PROMPT-ROOT): from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`) — run
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
git -C "{start}" rev-parse --show-toplevel
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
and use its one-line output. If the command fails (outside a git repository), `{worktree}` is the start directory itself. All paths below are relative to `{worktree}`.
|
|
295
|
+
|
|
296
|
+
**Step 1 — Read the index cache:**
|
|
297
|
+
|
|
298
|
+
Attempt to read `{worktree}/.devflow/features/index.md`. Each line follows the format:
|
|
299
|
+
|
|
300
|
+
```
|
|
301
|
+
- **{slug}** — {areas} — {Use-when description}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
If `index.md` exists and contains at least one entry line, use it for relevance matching.
|
|
305
|
+
|
|
306
|
+
**Step 2 — Fallback: glob frontmatter (if `index.md` is absent or empty):**
|
|
307
|
+
|
|
308
|
+
Glob `{worktree}/.devflow/features/*/KNOWLEDGE.md`. For each file found, read only its YAML frontmatter block (between the opening and closing `---` delimiters). The frontmatter fields `name`, `description`, and `directories` are the authoritative relevance surface — `index.md` is only a cache.
|
|
309
|
+
|
|
310
|
+
**Step 3 — Pick relevant KBs:**
|
|
311
|
+
|
|
312
|
+
Match the current task area and description against each index line (or frontmatter `description` + `directories` on fallback). Select entries whose documented area overlaps the current task. This is a relevance judgment — prefer specificity over breadth.
|
|
313
|
+
|
|
314
|
+
**Step 4 — Read each selected KB's Rules:**
|
|
315
|
+
|
|
316
|
+
For each selected entry, `{kb}` is `{worktree}/.devflow/features/{slug}/KNOWLEDGE.md`:
|
|
317
|
+
|
|
318
|
+
1. List its `##` headings with line numbers through Bash: `command grep -n '^## ' "{kb}"`. This only locates sections; the text of a KB comes from the Read view alone.
|
|
319
|
+
2. Read the `## Rules` range (its line to the next heading) with the Read tool, using `offset` and `limit`, and choose the one to three bullets most relevant to the current task. The choice is yours, made per KB.
|
|
320
|
+
3. If the KB has no `## Rules` section, choose one to three entries from its `## Anti-Patterns` or `## Gotchas` range the same way, and label them by that section's name instead of an ID.
|
|
321
|
+
|
|
322
|
+
When a KB contradicts the code you observe, **trust the code** — the code is the freshness mechanism; the KB may lag behind. A missing Rules section, a missing heading list and `(none)` are legitimate states, not errors.
|
|
323
|
+
|
|
324
|
+
**Step 5 — Set FEATURE_KNOWLEDGE and FEATURE_KNOWLEDGE_RULES:**
|
|
325
|
+
|
|
326
|
+
Write one block per selected KB. Paste each bullet verbatim from the Read view, never from a shell view. The path is relative to the checkout root; an agent resolves it under `WORKTREE_PATH` when one is provided.
|
|
327
|
+
|
|
328
|
+
```
|
|
329
|
+
--- Feature knowledge: {slug} ---
|
|
330
|
+
KB: .devflow/features/{slug}/KNOWLEDGE.md
|
|
331
|
+
Rules:
|
|
332
|
+
- **KB-AP-2** {bullet text, verbatim}
|
|
333
|
+
- **KB-INV-1** {bullet text, verbatim}
|
|
334
|
+
Headings: L5 Rules · L40 Overview · L62 Anti-Patterns · L118 Key Files
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
A KB with no Rules section labels its entries `Rules ({section name}):` and gives them no ID. `FEATURE_KNOWLEDGE` is these blocks; `FEATURE_KNOWLEDGE_RULES` is the same blocks without the `Headings:` line. Both come from this one selection, and each spawn names the variable its recipient takes. If no KBs exist, no KBs are relevant, or `.devflow/features/` is absent, set both to `(none)`.
|
|
338
|
+
|
|
339
|
+
**One git call, then direct reads — no `.cjs` script.** After resolving `{worktree}`, this step is 1 index read (or N frontmatter reads on fallback), plus one heading listing and one Rules read per selected KB, bounded by KB count.
|
|
340
|
+
|
|
341
|
+
Pass `FEATURE_KNOWLEDGE` to all Review agents.
|
|
342
|
+
|
|
343
|
+
### Phase 2: Run Reviews (Parallel)
|
|
344
|
+
|
|
345
|
+
**Produces:** REVIEW_FOCUS_OUTPUTS
|
|
346
|
+
**Requires:** DIFF_RANGE, REVIEW_DIR, TIMESTAMP, FEATURE_KNOWLEDGE, PR_DESCRIPTION, PRIOR_RESOLUTIONS, REVIEW_FOCUS_LIST, DIFF_CLASS, DIFF_FILES
|
|
347
|
+
|
|
348
|
+
Spawn Review agents **in a single message**, for the focus set `DIFF_CLASS` selects (max 20 per worktree):
|
|
349
|
+
|
|
350
|
+
- `code`: the 8 core reviews on the full `diff.patch`, plus the language and conditional focuses Phase 1 added.
|
|
351
|
+
- `docs-only`, `tests-only`, `lockfile-only`: only the reduced set Phase 1 names, each reading `diff.patch`; a mixed non-code diff runs the union. No language or conditional focus is spawned, whatever its trigger.
|
|
352
|
+
|
|
353
|
+
| Focus | Runs | Pattern Skill | DIFF_FILE |
|
|
354
|
+
|-------|------|---------------|-----------|
|
|
355
|
+
| security | ✓ | devflow:security | diff.patch |
|
|
356
|
+
| architecture | ✓ | devflow:architecture | diff.patch |
|
|
357
|
+
| performance | ✓ | devflow:performance | diff.patch |
|
|
358
|
+
| complexity | ✓ | devflow:complexity | diff.patch |
|
|
359
|
+
| consistency | ✓ | devflow:consistency | diff.patch |
|
|
360
|
+
| regression | ✓ | devflow:regression | diff.patch |
|
|
361
|
+
| testing | ✓ | devflow:testing | diff.patch |
|
|
362
|
+
| reliability | ✓ | devflow:reliability | diff.patch |
|
|
363
|
+
| typescript | stamp-gated | devflow:typescript | diff-typescript.patch |
|
|
364
|
+
| react | stamp-gated | devflow:react | diff-react.patch |
|
|
365
|
+
| accessibility | stamp-gated | devflow:accessibility | diff-accessibility.patch |
|
|
366
|
+
| ui-design | stamp-gated | devflow:ui-design | diff-ui-design.patch |
|
|
367
|
+
| go | stamp-gated | devflow:go | diff-go.patch |
|
|
368
|
+
| java | stamp-gated | devflow:java | diff-java.patch |
|
|
369
|
+
| python | stamp-gated | devflow:python | diff-python.patch |
|
|
370
|
+
| rust | stamp-gated | devflow:rust | diff-rust.patch |
|
|
371
|
+
| database | conditional | devflow:database | diff.patch |
|
|
372
|
+
| dependencies | conditional | devflow:dependencies | diff.patch |
|
|
373
|
+
| documentation | conditional | devflow:documentation | diff.patch |
|
|
374
|
+
| compliance | diff-driven | devflow:compliance | diff.patch |
|
|
375
|
+
|
|
376
|
+
Review agent count: `code` runs 8 core, +1-12 added by Phase 1 (max 20 total per worktree); a reduced class or a mix runs 2-6.
|
|
377
|
+
|
|
378
|
+
Each Review agent invocation (all in one message, **NOT background**):
|
|
379
|
+
```
|
|
380
|
+
Agent(subagent_type="Review", run_in_background=false):
|
|
381
|
+
"Review focusing on {focus}. Load the pattern skill via the Skill tool: Skill(skill="devflow:{focus}").
|
|
382
|
+
Follow 6-step process from devflow:review-methodology.
|
|
383
|
+
PR: #{pr_number}, Base: {base_branch}
|
|
384
|
+
WORKTREE_PATH: {worktree_path} (omit if cwd)
|
|
385
|
+
DIFF_FILE: {diff_file} (absolute: {REVIEW_DIR}/diff.patch, or {REVIEW_DIR}/diff-{focus}.patch for a language focus, per the table)
|
|
386
|
+
DIFF_RANGE: {DIFF_RANGE} (information only)
|
|
387
|
+
FEATURE_KNOWLEDGE: {feature_knowledge}
|
|
388
|
+
PR_DESCRIPTION: <pr-description>{pr_description}</pr-description>
|
|
389
|
+
PRIOR_RESOLUTIONS: <prior-resolution-summary>{prior_resolutions}</prior-resolution-summary>
|
|
390
|
+
COMPLIANCE_FRAMEWORKS: {COMPLIANCE_FRAMEWORKS} (compliance focus only)
|
|
391
|
+
If PRIOR_RESOLUTIONS is not (none), follow Cross-Cycle Awareness in review.md.
|
|
392
|
+
Follow devflow:apply-feature-knowledge for FEATURE_KNOWLEDGE — feature-specific patterns and anti-patterns inform findings.
|
|
393
|
+
IMPORTANT: Write report to {worktree_path}/.devflow/docs/reviews/{branch-slug}/{timestamp}/{focus}.md using Write tool"
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
In multi-worktree mode, process worktrees **sequentially** (one worktree at a time). Complete Phases 1-4 for each worktree before starting the next. This prevents agent overload — spawning 8-20 Review agents per worktree across multiple worktrees simultaneously overwhelms the system.
|
|
397
|
+
|
|
398
|
+
### Phase 3: Synthesis → Review Comment (Sequential)
|
|
399
|
+
|
|
400
|
+
**Produces:** REVIEW_SUMMARY, PR_COMMENT
|
|
401
|
+
**Requires:** REVIEW_FOCUS_OUTPUTS, REVIEW_DIR, PR_INFO
|
|
402
|
+
|
|
403
|
+
**WAIT** for Phase 2. For each worktree, run steps 3a and 3b in sequence:
|
|
404
|
+
|
|
405
|
+
**Step 3a — Synthesize agent** per worktree (wait for completion before 3b):
|
|
406
|
+
```
|
|
407
|
+
Agent(subagent_type="Synthesize", run_in_background=false):
|
|
408
|
+
"Mode: review
|
|
409
|
+
WORKTREE_PATH: {worktree_path} (omit if cwd)
|
|
410
|
+
REVIEW_BASE_DIR: {worktree_path}/.devflow/docs/reviews/{branch-slug}/{timestamp}
|
|
411
|
+
TIMESTAMP: {timestamp}
|
|
412
|
+
CYCLE_NUMBER: {cycle_number}
|
|
413
|
+
PRIOR_RESOLUTIONS: <prior-resolution-summary>{prior_resolutions}</prior-resolution-summary>
|
|
414
|
+
Include Convergence Status section in review-summary.md.
|
|
415
|
+
Aggregate findings, determine merge recommendation.
|
|
416
|
+
Output: {worktree_path}/.devflow/docs/reviews/{branch-slug}/{timestamp}/review-summary.md"
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
**Step 3b — Git agent (post-review-summary)** per worktree (after Step 3a writes review-summary.md):
|
|
420
|
+
```
|
|
421
|
+
Agent(subagent_type="Git", run_in_background=false):
|
|
422
|
+
"OPERATION: post-review-summary
|
|
423
|
+
PR_NUMBER: {pr_number}
|
|
424
|
+
REVIEW_SUMMARY_PATH: .devflow/docs/reviews/{branch-slug}/{timestamp}/review-summary.md
|
|
425
|
+
CYCLE_NUMBER: {cycle_number}
|
|
426
|
+
REVIEW_TIMESTAMP: {timestamp}
|
|
427
|
+
REVIEW_PUBLICATION: {REVIEW_PUBLICATION}
|
|
428
|
+
WORKTREE_PATH: {worktree_path} (omit if cwd)
|
|
429
|
+
Posts the consolidated review-summary comment (marker-deduped by the operation on the cycle+timestamp pair)."
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Phase 4: Write Review Head Marker & Report
|
|
433
|
+
|
|
434
|
+
**Requires:** BRANCH_INFO, REVIEW_DIR
|
|
435
|
+
|
|
436
|
+
Per worktree, after successful completion:
|
|
437
|
+
1. Write current HEAD SHA to `{worktree_path}/.devflow/docs/reviews/{branch-slug}/.last-review-head`
|
|
438
|
+
2. Display results from all agents:
|
|
439
|
+
- Merge recommendation (from Synthesize agent)
|
|
440
|
+
- Issue counts by category (🔴 blocking / ⚠️ should-fix / ℹ️ pre-existing)
|
|
441
|
+
- Review comment status: POSTED / POSTED+TRUNCATED (body exceeded 60k after redaction) / SKIPPED (D7 dedup) / DEGRADED (from Git)
|
|
442
|
+
- 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)
|
|
443
|
+
- Artifact paths
|
|
444
|
+
|
|
445
|
+
In multi-worktree mode, report results per worktree.
|
|
446
|
+
|
|
447
|
+
## Architecture
|
|
448
|
+
|
|
449
|
+
```
|
|
450
|
+
/code-review (orchestrator - spawns agents only)
|
|
451
|
+
│
|
|
452
|
+
├─ Phase 0: Worktree Discovery & Pre-flight
|
|
453
|
+
│ ├─ Step 0a: git worktree list → filter reviewable
|
|
454
|
+
│ ├─ Step 0b: Resolve the compliance lens
|
|
455
|
+
│ ├─ Step 0c: Git agent (ensure-pr-ready) per worktree [parallel]
|
|
456
|
+
│ ├─ Step 0d: Incremental detection + timestamp setup per worktree
|
|
457
|
+
│ ├─ Step 0e-i: Load prior resolution-summary.md
|
|
458
|
+
│ ├─ Step 0e-ii: Convergence assessment (warn if FP ratio > 70%)
|
|
459
|
+
│ └─ Step 0f: Resolve REVIEW_PUBLICATION per worktree (publication gate)
|
|
460
|
+
│
|
|
461
|
+
├─ Per worktree (SEQUENTIAL — one worktree at a time):
|
|
462
|
+
│ │
|
|
463
|
+
│ ├─ Phase 1: Analyze changed files
|
|
464
|
+
│ │ ├─ Classify the diff (paths.txt → DIFF_CLASS)
|
|
465
|
+
│ │ ├─ Choose the focuses (code class: file types + the language stamp)
|
|
466
|
+
│ │ └─ Write diff.patch and diff-{focus}.patch, by redirect
|
|
467
|
+
│ │
|
|
468
|
+
│ ├─ Phase 2: Reviews (PARALLEL within worktree)
|
|
469
|
+
│ │ ├─ code: Review agents security, architecture, performance, complexity,
|
|
470
|
+
│ │ │ consistency, regression, testing, reliability (diff.patch)
|
|
471
|
+
│ │ ├─ code: + language (diff-{focus}.patch) and conditional Review agents
|
|
472
|
+
│ │ └─ docs-only / tests-only / lockfile-only: the reduced set (diff.patch)
|
|
473
|
+
│ │
|
|
474
|
+
│ ├─ Phase 3: Synthesis → Review Comment (SEQUENTIAL within worktree)
|
|
475
|
+
│ │ ├─ Step 3a: Synthesize agent (mode: review, writes review-summary.md)
|
|
476
|
+
│ │ └─ Step 3b: Git agent (post-review-summary, D7 marker-dedup, REVIEW_PUBLICATION)
|
|
477
|
+
│ │
|
|
478
|
+
│ └─ Phase 4: Write .last-review-head + display results
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
## Edge Cases
|
|
482
|
+
|
|
483
|
+
| Case | Handling |
|
|
484
|
+
|------|----------|
|
|
485
|
+
| No new commits since last review | Skip review, report: "No new commits since last review. Use --full for a full re-review." |
|
|
486
|
+
| Rebase invalidates `.last-review-head` SHA | `git cat-file -t` check fails → fallback to full diff |
|
|
487
|
+
| Same-minute review collision | `mkdir` fails → retry with seconds appended (`YYYY-MM-DD_HHMMSS`) |
|
|
488
|
+
| Worktree in detached HEAD | Filtered out (no branch name → not reviewable) |
|
|
489
|
+
| Worktree mid-rebase or mid-merge | Filtered out by status check |
|
|
490
|
+
| Two worktrees on same branch | Deduplicate by branch — review once, use first worktree's path |
|
|
491
|
+
| Worktree on protected branch | Filtered out (not reviewable) |
|
|
492
|
+
| Worktree pre-flight fails | Report failure, continue with other worktrees |
|
|
493
|
+
| `--full` in multi-worktree mode | Applies to all worktrees (global modifier) |
|
|
494
|
+
| Many worktrees (5+) | Report count and proceed — user manages their worktree count |
|
|
495
|
+
| 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 |
|
|
496
|
+
| First review (no prior resolution) | PRIOR_RESOLUTIONS=(none), no convergence check |
|
|
497
|
+
| fp_ratio denominator = 0 | fp_ratio = 0, no warning |
|
|
498
|
+
| `--full` flag | Bypass incremental detection (Step 0d), still load PRIOR_RESOLUTIONS for cross-cycle awareness |
|
|
499
|
+
| Parsing failure on resolution-summary.md | fp_ratio = 0, convergence tracking degraded (see Step 0e-ii) |
|
|
500
|
+
| Concurrent sessions | Advisory only, each session computes independently |
|
|
501
|
+
| Docs-only diff | `docs-only`: documentation, consistency, security on `diff.patch`; no language or conditional focus |
|
|
502
|
+
| Tests-only diff | `tests-only`: testing, reliability, consistency, security on `diff.patch`; no language or conditional focus |
|
|
503
|
+
| Lockfile-only diff | `lockfile-only`: dependencies, security on `diff.patch` |
|
|
504
|
+
| Mixed non-code diff (docs with tests, tests with a lockfile) | The union of the matching sets, on `diff.patch` |
|
|
505
|
+
| A path matching no class pattern, or an empty path list | `code` (fail-safe): the 8 core focuses on the full diff |
|
|
506
|
+
| A file moved across classes | `--no-renames` lists the old and the new path, so a code path makes the diff `code` |
|
|
507
|
+
| Path listing above about 40 lines | The count is printed; `paths.txt` is read in ranges of about 40 lines |
|
|
508
|
+
| Language files changed, plugin not installed | The focus is absent from the stamped line: not spawned |
|
|
509
|
+
| Public repo (`auto` mode) | Git agent probes visibility, posts counts-only STUB comment; full report stays local |
|
|
510
|
+
| `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 |
|
|
511
|
+
|
|
512
|
+
## Backwards Compatibility
|
|
513
|
+
|
|
514
|
+
- **Single worktree**: Auto-discovery finds only one worktree → proceeds exactly as before. Zero behavior change.
|
|
515
|
+
- **Legacy flat layout**: If `{worktree}/.devflow/docs/reviews/{branch-slug}/` contains flat `*.md` files (no timestamped subdirectories), new runs create timestamped subdirectories. Old flat files remain untouched.
|
|
516
|
+
|
|
517
|
+
## Principles
|
|
518
|
+
|
|
519
|
+
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
|
|
520
|
+
2. **Parallel, not background** - Multiple agents in one message, but `run_in_background=false` so phases complete before proceeding
|
|
521
|
+
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
|
|
522
|
+
4. **Clear ownership** - Each agent owns its output completely
|
|
523
|
+
5. **Honest reporting** - Display agent outputs directly
|
|
524
|
+
6. **Incremental by default** - Only review new changes unless `--full` specified
|
|
525
|
+
7. **Auto-discover worktrees** - One command handles all reviewable branches
|