claude-dev-env 1.26.0 → 1.26.2
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/hooks/blocking/code_rules_enforcer.py +5 -1
- package/hooks/blocking/test_code_rules_enforcer.py +61 -0
- package/hooks/blocking/test_code_rules_enforcer_file_global_constants.py +4 -2
- package/hooks/notification/subagent_complete_notify.py +5 -5
- package/hooks/notification/test_subagent_complete_notify.py +7 -0
- package/hooks/validators/git_checks.py +4 -1
- package/hooks/validators/test_output_formatter.py +7 -2
- package/package.json +1 -1
- package/skills/bugteam/SKILL.md +143 -309
- package/skills/bugteam/SKILL_EVALS.md +46 -46
- package/skills/bugteam/reference/README.md +13 -0
- package/skills/bugteam/reference/audit-and-teammates.md +127 -0
- package/skills/bugteam/reference/design-rationale.md +28 -0
- package/skills/bugteam/reference/github-pr-reviews.md +86 -0
- package/skills/bugteam/reference/team-setup.md +51 -0
- package/skills/bugteam/reference/teardown-publish-permissions.md +70 -0
- package/skills/bugteam/scripts/README.md +4 -0
- package/skills/bugteam/{_claude_permissions_common.py → scripts/_claude_permissions_common.py} +37 -33
- package/skills/bugteam/scripts/bugteam_code_rules_gate.py +55 -0
- package/skills/bugteam/{grant_project_claude_permissions.py → scripts/grant_project_claude_permissions.py} +10 -11
- package/skills/bugteam/{revoke_project_claude_permissions.py → scripts/revoke_project_claude_permissions.py} +13 -14
- package/skills/bugteam/sources.md +93 -0
- /package/hooks/validators/{config.py → validator_defaults.py} +0 -0
- /package/skills/bugteam/{test_claude_permissions_common.py → scripts/test_claude_permissions_common.py} +0 -0
package/skills/bugteam/SKILL.md
CHANGED
|
@@ -1,79 +1,77 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bugteam
|
|
3
3
|
description: >-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Triggers: '/bugteam',
|
|
12
|
-
'auto-fix the PR until clean', 'loop audit and fix'.
|
|
4
|
+
Claude Code agent team on the open pull request: run the CODE_RULES gate,
|
|
5
|
+
spawn a fresh clean-room audit (code-quality-agent, sonnet) and a fix pass
|
|
6
|
+
(clean-coder, sonnet), post per-loop GitHub review threads from teammates,
|
|
7
|
+
stop at zero findings or a 10-audit safety cap. Grants then revokes
|
|
8
|
+
`.claude/**` edit permission around the run. SKILL.md is the orchestration
|
|
9
|
+
checklist; `reference/` holds expanded prose by domain; CONSTRAINTS,
|
|
10
|
+
PROMPTS, EXAMPLES, and sources are companion files. Requires
|
|
11
|
+
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1. Triggers: '/bugteam',
|
|
12
|
+
'run the bug team', 'auto-fix the PR until clean', 'loop audit and fix'.
|
|
13
13
|
---
|
|
14
14
|
|
|
15
15
|
# Bugteam
|
|
16
16
|
|
|
17
|
-
**Core principle:**
|
|
17
|
+
**Core principle:** Agent team runs audit–fix until convergence. Bugfind: clean-room audit (fresh context each loop). Bugfix: addresses findings. Hard cap: 10 audit loops. Grant `.claude/**` permissions at start, revoke always at end.
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
> **Why agent teams, not parallel subagents:** Subagents return their results into the lead's context, which accumulates across loops. Agent team teammates are independent sessions with their own context windows and do not pollute the lead. The lead can shut down + respawn each loop, guaranteeing every audit starts fresh. Per the docs: *"Use subagents when you need quick, focused workers that report back. Use agent teams when teammates need to share findings, challenge each other, and coordinate on their own."* For this skill, the independent-context property is what we need; parallel subagents fail the clean-room requirement.
|
|
19
|
+
Subagents fold back into the lead context; agent-team teammates do not — that separation is the clean-room guarantee. Verbatim doc quotes and URLs: [`sources.md`](sources.md).
|
|
22
20
|
|
|
23
21
|
## Contents
|
|
24
22
|
|
|
25
|
-
|
|
23
|
+
Orchestration lives here; companion files hold prompts, invariants, examples, citations, and domain reference notes. Scan this list before a partial read.
|
|
26
24
|
|
|
27
25
|
- When this skill applies — refusal cases (4) and trigger conditions
|
|
28
|
-
- Utility scripts — pre-flight
|
|
29
|
-
- Pre-audit
|
|
30
|
-
- The Process —
|
|
26
|
+
- Utility scripts — pre-flight (`scripts/`, executed not inlined)
|
|
27
|
+
- Pre-audit gate — `validate_content` before each AUDIT
|
|
28
|
+
- The Process — checklist + Steps 0–6
|
|
31
29
|
- Step 0 — Grant project permissions
|
|
32
30
|
- Step 1 — Resolve PR scope
|
|
33
31
|
- Step 2 — Create the agent team
|
|
34
|
-
- Step 2.5 — PR comment lifecycle (per-loop review
|
|
35
|
-
- Step 3 —
|
|
36
|
-
- Step 4 —
|
|
37
|
-
- Step 4.5 —
|
|
38
|
-
- Step 5 — Revoke
|
|
39
|
-
- Step 6 —
|
|
40
|
-
- [`PROMPTS.md`](PROMPTS.md) —
|
|
41
|
-
- [`EXAMPLES.md`](EXAMPLES.md) —
|
|
42
|
-
- [`CONSTRAINTS.md`](CONSTRAINTS.md) — invariants
|
|
32
|
+
- Step 2.5 — PR comment lifecycle (per-loop review + fix replies)
|
|
33
|
+
- Step 3 — Cycle (AUDIT ↔ FIX, exits)
|
|
34
|
+
- Step 4 — Teardown + clean tree
|
|
35
|
+
- Step 4.5 — PR body via `pr-description-writer`
|
|
36
|
+
- Step 5 — Revoke permissions
|
|
37
|
+
- Step 6 — Final report
|
|
38
|
+
- [`PROMPTS.md`](PROMPTS.md) — spawn XML, categories A–J, outcome schemas
|
|
39
|
+
- [`EXAMPLES.md`](EXAMPLES.md) — exit scenarios
|
|
40
|
+
- [`CONSTRAINTS.md`](CONSTRAINTS.md) — invariants and design rationale
|
|
41
|
+
- [`sources.md`](sources.md) — doc URLs and verbatim quotes
|
|
42
|
+
- [`reference/README.md`](reference/README.md) — expanded prose by topic (design, team setup, GitHub reviews, cycle, teardown)
|
|
43
43
|
|
|
44
44
|
## When this skill applies
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
`/bugteam` once authorizes the full cycle (up to 10 audits + fixes).
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
Refusals — first match wins; respond with the quoted line exactly and stop:
|
|
49
49
|
|
|
50
|
-
- **Agent teams not enabled.** Check `claude config get env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` and `~/.claude/settings.json`. If neither
|
|
51
|
-
- **
|
|
52
|
-
- **
|
|
53
|
-
- **
|
|
50
|
+
- **Agent teams not enabled.** Check `claude config get env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` and `~/.claude/settings.json`. If neither is `"1"`: `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 not set. /bugteam requires the agent teams feature. See https://code.claude.com/docs/en/agent-teams#enable-agent-teams.`
|
|
51
|
+
- **No PR or upstream diff.** `No PR or upstream diff. /bugteam needs a target.`
|
|
52
|
+
- **Dirty tree.** `Uncommitted changes detected. Stash, commit, or revert before /bugteam.`
|
|
53
|
+
- **Missing subagents.** Before Step 0, confirm `code-quality-agent` and `clean-coder` exist. Else: `Required subagent type <name> not installed. /bugteam needs both code-quality-agent and clean-coder available.`
|
|
54
54
|
|
|
55
55
|
## Utility scripts
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
### Pre-flight (recommended before Step 0)
|
|
57
|
+
Shell-heavy steps live under `scripts/` (run, do not paste into context). Utility scripts are **executed**, not loaded as primary context ([`sources.md`](sources.md) § Progressive disclosure and utility scripts). [`scripts/README.md`](scripts/README.md).
|
|
60
58
|
|
|
61
|
-
|
|
59
|
+
### Pre-flight (before Step 0)
|
|
62
60
|
|
|
63
61
|
```bash
|
|
64
62
|
python "${CLAUDE_SKILL_DIR}/scripts/bugteam_preflight.py"
|
|
65
63
|
```
|
|
66
64
|
|
|
67
|
-
|
|
65
|
+
Non-zero → fix before grant. `BUGTEAM_PREFLIGHT_SKIP=1` emergency only. `--pre-commit` if `.pre-commit-config.yaml` exists.
|
|
68
66
|
|
|
69
67
|
## The Process
|
|
70
68
|
|
|
71
|
-
### Progress checklist
|
|
69
|
+
### Progress checklist
|
|
72
70
|
|
|
73
71
|
```
|
|
74
72
|
[ ] Step 0: project permissions granted
|
|
75
73
|
[ ] Step 1: PR scope resolved
|
|
76
|
-
[ ] Step 2: agent team created +
|
|
74
|
+
[ ] Step 2: agent team created + loop state set
|
|
77
75
|
[ ] Step 3: cycle complete (converged | cap reached | stuck | error)
|
|
78
76
|
[ ] Step 4: team torn down + working tree clean
|
|
79
77
|
[ ] Step 4.5: PR description rewritten (or skip warning logged)
|
|
@@ -81,33 +79,27 @@ If the exit code is non-zero, stop and fix failing checks before granting permis
|
|
|
81
79
|
[ ] Step 6: final report printed
|
|
82
80
|
```
|
|
83
81
|
|
|
84
|
-
### Step 0: Grant project permissions (
|
|
85
|
-
|
|
86
|
-
Before spawning any teammates, grant the team session write access to the project's `.claude/**` tree:
|
|
82
|
+
### Step 0: Grant project permissions (once, first)
|
|
87
83
|
|
|
88
84
|
```bash
|
|
89
|
-
python "${CLAUDE_SKILL_DIR}/grant_project_claude_permissions.py"
|
|
85
|
+
python "${CLAUDE_SKILL_DIR}/scripts/grant_project_claude_permissions.py"
|
|
90
86
|
```
|
|
91
87
|
|
|
92
|
-
|
|
88
|
+
`${CLAUDE_SKILL_DIR}` is host-substituted before the shell runs (unlike normal env expansion). Idempotent writes to `~/.claude/settings.json` from repo root. Non-zero → stop. Revoke in Step 5 on every exit path.
|
|
93
89
|
|
|
94
|
-
|
|
90
|
+
### Step 1: Resolve PR scope (once)
|
|
95
91
|
|
|
96
|
-
|
|
92
|
+
Same as `/findbugs`:
|
|
97
93
|
|
|
98
|
-
|
|
94
|
+
1. `gh pr view --json number,baseRefName,headRefName,url`
|
|
95
|
+
2. Else `git merge-base HEAD origin/<default>` then `git diff <merge-base>...HEAD`
|
|
96
|
+
3. Else refuse above.
|
|
99
97
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
1. `gh pr view --json number,baseRefName,headRefName,url` from the working directory.
|
|
103
|
-
2. Fall back to `git merge-base HEAD origin/<default>` then `git diff <merge-base>...HEAD`.
|
|
104
|
-
3. Neither → refuse per the refusal cases above.
|
|
105
|
-
|
|
106
|
-
Capture: `<owner>/<repo>`, head branch, base branch, PR number, PR URL. This scope persists across every loop — `/bugteam` runs to completion from the single up-front confirmation.
|
|
98
|
+
Keep: owner/repo, branches, PR number, URL — for all loops.
|
|
107
99
|
|
|
108
100
|
### Step 2: Create the agent team
|
|
109
101
|
|
|
110
|
-
|
|
102
|
+
Lead calls `TeamCreate`:
|
|
111
103
|
|
|
112
104
|
```
|
|
113
105
|
TeamCreate(
|
|
@@ -117,163 +109,114 @@ TeamCreate(
|
|
|
117
109
|
)
|
|
118
110
|
```
|
|
119
111
|
|
|
120
|
-
|
|
112
|
+
**Team name:** `bugteam-pr-<number>-<YYYYMMDDHHMMSS>` or `bugteam-<sanitized-head>-<YYYYMMDDHHMMSS>` if no PR. Timestamp avoids collisions. `TeamCreate` implements natural-language team creation ([`sources.md`](sources.md) § Team creation in natural language).
|
|
121
113
|
|
|
122
|
-
|
|
114
|
+
**Sanitize head branch (no-PR only):** replace characters outside `[A-Za-z0-9._-]` with `-` (e.g. `feat/foo*bar` → `feat-foo-bar`). Apply once; reuse everywhere below.
|
|
123
115
|
|
|
124
|
-
|
|
125
|
-
- **Branch-name sanitization (no-PR fallback only):** Before substituting `<head-branch>` into the team_name template, replace every character outside `[A-Za-z0-9._-]` with `-`. The whitelist keeps safe portable filename characters only; OS-reserved and shell-special characters (`/ \ : * ? < > | "` plus ASCII control chars 0x00–0x1F) fall outside the whitelist and become `-`. Example: `feat/foo*bar` → `feat-foo-bar`; team_name becomes `bugteam-feat-foo-bar-<YYYYMMDDHHMMSS>`. Apply the sanitization when team_name is first assembled so every downstream use (team creation, scoped temp dir, cleanup) sees the safe form.
|
|
126
|
-
- **Per-team temp directory (resolved once, reused everywhere):** After team_name is captured, resolve a portable absolute path with a Claude-side lookup using Python's `tempfile.gettempdir()`, which honors `TMPDIR`, `TEMP`, and `TMP` in the platform-correct order and falls back to `C:\Users\<user>\AppData\Local\Temp` on Windows or `/tmp` on Unix: `Path(tempfile.gettempdir()) / team_name` (requires `import tempfile`). The `team_name` value already carries the `bugteam-` prefix, so keep it as-is here. Let `tempfile.gettempdir()` do the lookup; use its result directly. Capture the resolved absolute path as `<team_temp_dir>` and pass that literal path to every shell command that follows. Claude performs all temp-root resolution, so every shell (bash, cmd.exe, PowerShell) receives the same literal absolute value.
|
|
127
|
-
- **Roles defined up front (spawned per loop, not at team creation):**
|
|
128
|
-
- `bugfind` — uses teammate role `code-quality-agent`, model sonnet
|
|
129
|
-
- `bugfix` — uses teammate role `clean-coder`, model sonnet
|
|
130
|
-
- **Display mode:** inherit user's default (`teammateMode` in `~/.claude.json`); do not override.
|
|
116
|
+
**`<team_temp_dir>`:** `Path(tempfile.gettempdir()) / team_name` (lead resolves once to an absolute path; every shell gets that literal string).
|
|
131
117
|
|
|
132
|
-
|
|
118
|
+
**Roles (spawned per loop, not here):** bugfind → `code-quality-agent` sonnet; bugfix → `clean-coder` sonnet. **Display:** inherit `teammateMode` from `~/.claude.json`. Reference subagent types by name when spawning teammates ([`sources.md`](sources.md) § Referencing subagent types when spawning teammates).
|
|
133
119
|
|
|
134
|
-
|
|
120
|
+
**Loop state (lead; not a single script):**
|
|
135
121
|
|
|
136
122
|
```bash
|
|
137
123
|
loop_count=0
|
|
138
124
|
last_action="fresh"
|
|
139
125
|
last_findings=""
|
|
140
126
|
audit_log=""
|
|
141
|
-
starting_sha="$(git rev-parse HEAD)"
|
|
142
|
-
team_name="bugteam-pr-<number>-<YYYYMMDDHHMMSS>"
|
|
143
|
-
team_temp_dir="<
|
|
144
|
-
loop_comment_index=""
|
|
127
|
+
starting_sha="$(git rev-parse HEAD)"
|
|
128
|
+
team_name="bugteam-pr-<number>-<YYYYMMDDHHMMSS>"
|
|
129
|
+
team_temp_dir="<absolute-path>/<team_name>"
|
|
130
|
+
loop_comment_index=""
|
|
145
131
|
```
|
|
146
132
|
|
|
147
|
-
**`loop_comment_index
|
|
148
|
-
|
|
149
|
-
Each entry: `{loop, finding_id, finding_comment_id, finding_comment_url, used_fallback, fix_status}`. Populated by AUDIT, consumed by FIX.
|
|
150
|
-
|
|
151
|
-
### Step 2.5: PR comment lifecycle (one review per loop)
|
|
152
|
-
|
|
153
|
-
The team narrates its work to the PR via a **GitHub pull-request review** per loop so findings render as a tree under a single parent review (like Cursor Bugbot). **Teammates own all PR comment posting** — bugfind posts the review (parent body + child finding comments in one batched POST), bugfix posts fix replies. All comment, review, and reply POSTs belong to the teammates. The lead's single PR-write action is the final description rewrite at Step 4.5 (via `pr-description-writer` agent).
|
|
154
|
-
|
|
155
|
-
- **Per-loop review** — one `POST /pulls/<number>/reviews` per loop, posted by the bugfind teammate AFTER auditing. The review body is the loop header (with audit counts); the review's `comments[]` array holds one anchored finding per P0/P1/P2 finding. GitHub renders this as a single collapsible thread with each finding as a child comment — the tree shape Cursor Bugbot produces.
|
|
156
|
-
|
|
157
|
-
- **Fix replies** — replies to each child finding comment. Posted by the bugfix teammate after the commit lands. Body: `Fixed in <commit_sha>` if addressed, or `Could not address this loop: <one-line reason>` if not. The `/pulls/<number>/comments/<id>/replies` endpoint works on any review comment, including those created as part of a review, so this shape is unchanged.
|
|
158
|
-
|
|
159
|
-
**Ordering:** bugfind audits FIRST, buffers the findings, validates anchors against the captured diff, then posts the review ONCE at the end. The review body names the finding count authoritatively. Keep all posting bunched into that single end-of-loop review POST.
|
|
133
|
+
**`loop_comment_index`:** reset each AUDIT start; filled during AUDIT; FIX consumes for replies; cleared after FIX. Entries: `{loop, finding_id, finding_comment_id, finding_comment_url, used_fallback, fix_status}`.
|
|
160
134
|
|
|
161
|
-
|
|
135
|
+
### Step 2.5: PR comments (one review per loop)
|
|
162
136
|
|
|
163
|
-
|
|
137
|
+
Bugfind posts one `POST .../pulls/<n>/reviews` per loop after audit (body + `comments[]` for anchored P0/P1/P2). Bugfix posts `.../comments/<id>/replies` after push. Lead’s only PR write: Step 4.5 body edit.
|
|
164
138
|
|
|
165
|
-
|
|
166
|
-
jq -n \
|
|
167
|
-
--rawfile review_body <tmp_review_body.md> \
|
|
168
|
-
--arg commit_id "$(git rev-parse HEAD)" \
|
|
169
|
-
--rawfile finding_body_1 <tmp_finding_1.md> \
|
|
170
|
-
--arg path_1 "<file_1>" \
|
|
171
|
-
--argjson line_1 <line_1> \
|
|
172
|
-
[... one finding_body_K / path_K / line_K triple per anchored finding ...] \
|
|
173
|
-
'{
|
|
174
|
-
commit_id: $commit_id,
|
|
175
|
-
event: "COMMENT",
|
|
176
|
-
body: $review_body,
|
|
177
|
-
comments: [
|
|
178
|
-
{path: $path_1, line: $line_1, side: "RIGHT", body: $finding_body_1}
|
|
179
|
-
[, ... one object per anchored finding ...]
|
|
180
|
-
]
|
|
181
|
-
}' \
|
|
182
|
-
| gh api repos/<owner>/<repo>/pulls/<number>/reviews -X POST --input -
|
|
183
|
-
```
|
|
139
|
+
Order: audit → buffer → validate anchors vs diff → single review POST. Review body states counts; zero findings → still one review, `comments: []`, body `## /bugteam loop <N> audit: 0P0 / 0P1 / 0P2 → clean`.
|
|
184
140
|
|
|
185
|
-
|
|
141
|
+
**Payloads:** build JSON with `jq --rawfile` / `-Rs`, pipe to `gh api ... --input -` (avoids shell-quoting; satisfies `gh-body-backtick-guard`). Write each markdown body to a temp file first.
|
|
186
142
|
|
|
187
|
-
|
|
143
|
+
**Review POST** (one `comments[]` object per anchored finding; single-line `{path, line, side: "RIGHT", body}`; multi-line add `start_line`, `start_side: "RIGHT"`):
|
|
188
144
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
145
|
+
```
|
|
146
|
+
jq -n \
|
|
147
|
+
--rawfile review_body <tmp_review_body.md> \
|
|
148
|
+
--arg commit_id "$(git rev-parse HEAD)" \
|
|
149
|
+
--rawfile finding_body_1 <tmp_finding_1.md> \
|
|
150
|
+
--arg path_1 "<file_1>" \
|
|
151
|
+
--argjson line_1 <line_1> \
|
|
152
|
+
[... one finding_body_K / path_K / line_K triple per finding ...] \
|
|
153
|
+
'{
|
|
154
|
+
commit_id: $commit_id,
|
|
155
|
+
event: "COMMENT",
|
|
156
|
+
body: $review_body,
|
|
157
|
+
comments: [
|
|
158
|
+
{path: $path_1, line: $line_1, side: "RIGHT", body: $finding_body_1}
|
|
159
|
+
[, ... ]
|
|
160
|
+
]
|
|
161
|
+
}' \
|
|
162
|
+
| gh api repos/<owner>/<repo>/pulls/<number>/reviews -X POST --input -
|
|
163
|
+
```
|
|
195
164
|
|
|
196
|
-
|
|
197
|
-
jq -Rs '{body: .}' < <tmp_fallback.md> \
|
|
198
|
-
| gh api repos/<owner>/<repo>/issues/<number>/comments -X POST --input -
|
|
199
|
-
```
|
|
165
|
+
**Fix reply:** `jq -Rs '{body: .}' <tmp_reply.md | gh api repos/<owner>/<repo>/pulls/<number>/comments/<finding_comment_id>/replies -X POST --input -`
|
|
200
166
|
|
|
201
|
-
|
|
167
|
+
**Review POST fails:** issue comment fallback: `jq -Rs '{body: .}' <tmp_fallback.md | gh api repos/<owner>/<repo>/issues/<number>/comments -X POST --input -`
|
|
202
168
|
|
|
203
|
-
|
|
169
|
+
`<head_sha_at_post_time>`: `git rev-parse HEAD` in teammate cwd immediately before POST.
|
|
204
170
|
|
|
205
|
-
**Review body
|
|
171
|
+
**Review body template (`<tmp_review_body.md>`):**
|
|
206
172
|
|
|
207
173
|
```
|
|
208
174
|
## /bugteam loop <N> audit: <P0>P0 / <P1>P1 / <P2>P2
|
|
209
175
|
|
|
210
|
-
<if any findings could not be anchored to a diff line, include this section:>
|
|
211
176
|
### Findings without a diff anchor
|
|
212
|
-
|
|
177
|
+
(only if needed)
|
|
213
178
|
- **[severity] title** — <file>:<line> — <one-line description>
|
|
214
179
|
```
|
|
215
180
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
**Anchor-validation fallback (teammate handles).** GitHub rejects the entire review POST if any `comments[]` entry targets a line not in the diff. Before posting, the bugfind teammate validates every finding's `(file, line)` against the captured diff. Findings whose anchor is not in the diff are NOT added to `comments[]`; they are listed in the review body under `### Findings without a diff anchor`. The outcome XML records `used_fallback="true"` for each such finding, with `finding_comment_id=""` and `finding_comment_url=<review_url>` (the parent review URL, since no child comment exists for it). The teammate logs the fallback count in its outcome XML so the lead's final report can count fallbacks. Cycle continues; no anchor failure aborts the loop.
|
|
219
|
-
|
|
220
|
-
**Review POST failure fallback.** If the review POST itself fails (rate limit, network, malformed payload), the teammate falls back to a single top-level issue comment containing the review body plus every finding inline (severity, file:line, description). Every finding in that run carries `used_fallback="true"` and the issue-comment URL as `finding_comment_url`. Use the Review-POST failure fallback CLI shape above (`jq -Rs | gh api .../issues/<number>/comments --input -`).
|
|
181
|
+
**Anchor fallback:** lines not in diff → omit from `comments[]`, list under `### Findings without a diff anchor`; outcome `used_fallback="true"`, empty `finding_comment_id`, `finding_comment_url` = parent review URL.
|
|
221
182
|
|
|
222
|
-
**
|
|
183
|
+
**POST failure fallback:** one issue comment with full text; all findings `used_fallback="true"`, URLs = issue comment.
|
|
223
184
|
|
|
224
|
-
|
|
225
|
-
- Fix reply: `POST /repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies` (required: `body`)
|
|
226
|
-
- Review-POST failure fallback: `POST /repos/{owner}/{repo}/issues/{issue_number}/comments` (required: `body`; `{issue_number}` is the PR number)
|
|
185
|
+
**Endpoints:** `POST .../pulls/{pull}/reviews`; `POST .../pulls/{pull}/comments/{id}/replies`; fallback `POST .../issues/{issue}/comments` (`issue` = PR number).
|
|
227
186
|
|
|
228
187
|
### Step 3: The cycle
|
|
229
188
|
|
|
230
|
-
Repeat until
|
|
189
|
+
Repeat until exit. **Gate:** `validate_content` / `hooks/blocking/code_rules_enforcer.py` on PR-scoped files before every AUDIT (`bugteam_code_rules_gate.py`). Lead runs gate; clean-coder clears failures; then bugfind audits.
|
|
231
190
|
|
|
232
|
-
|
|
191
|
+
1. From `last_action` / `last_findings`:
|
|
192
|
+
- `last_action == "audited"` and `last_findings.total == 0` → exit `converged`
|
|
193
|
+
- `last_action == "fixed"` and `git rev-parse HEAD` unchanged since pre-FIX → exit `stuck`
|
|
194
|
+
- `last_action in {"fresh", "fixed"}` → **pre-audit** then **AUDIT**
|
|
195
|
+
- `last_action == "audited"` and `last_findings.total > 0` → **FIX**
|
|
233
196
|
|
|
234
|
-
|
|
235
|
-
- `last_action == "audited"` and `last_findings.total == 0` → exit reason = `converged`
|
|
236
|
-
- `last_action == "fixed"` and `git rev-parse HEAD` did not change since pre-FIX → exit reason = `stuck` (see FIX action)
|
|
237
|
-
- `last_action in {"fresh", "fixed"}` → go to **pre-audit path** (below), then **AUDIT**
|
|
238
|
-
- `last_action == "audited"` and `last_findings.total > 0` → go to **FIX** (below)
|
|
197
|
+
2. **Pre-audit** (only when the next step is AUDIT):
|
|
239
198
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
```bash
|
|
244
|
-
python "${CLAUDE_SKILL_DIR}/scripts/bugteam_code_rules_gate.py" --base origin/<baseRefName>
|
|
245
|
-
```
|
|
199
|
+
```bash
|
|
200
|
+
python "${CLAUDE_SKILL_DIR}/scripts/bugteam_code_rules_gate.py" --base origin/<baseRefName>
|
|
201
|
+
```
|
|
246
202
|
|
|
247
|
-
|
|
248
|
-
2. If exit code **0** → continue to step 3 (AUDIT spawn) below.
|
|
249
|
-
3. If exit code **non-zero** → spawn a NEW **clean-coder** teammate — **standards-fix pass** — with instructions: read the script’s stderr, edit the repo until a **re-run** of the **same** gate command exits **0**, then one commit, `git push`, shutdown. Repeat standards-fix spawns until the gate exits **0** or **5** failed gate rounds (each round = one teammate session after a non-zero gate). If still non-zero after 5 rounds → exit reason = `error: code rules gate failed pre-audit`.
|
|
250
|
-
4. After gate exit **0**, increment `loop_count`. If `loop_count > 10`, exit reason = `cap reached` (counts **audits**, not standards-only rounds).
|
|
251
|
-
5. Execute **AUDIT action** (spawn bugfind). Print progress: `Loop <N> audit: ...`
|
|
203
|
+
Lead only; merge-base / diff details in [`scripts/README.md`](scripts/README.md). Non-zero → spawn **clean-coder** standards-fix (read stderr, edit, re-run **this same** command, one commit, `git push`, shutdown) until exit **0** or **5** failed gate rounds → `error: code rules gate failed pre-audit`. After **0**: `loop_count += 1`; if `loop_count > 10` → `cap reached`. Then **AUDIT** (bugfind); print `Loop <N> audit: ...`.
|
|
252
204
|
|
|
253
|
-
3. **FIX
|
|
254
|
-
1. Increment `loop_count`. If `loop_count > 10`, exit reason = `cap reached`.
|
|
255
|
-
2. Execute **FIX action** (spawn bugfix clean-coder for audit findings). Print: `Loop <N> fix: commit ...`
|
|
256
|
-
3. Set `last_action = "fixed"`, update `audit_log`, loop to step 1 (next iteration will hit **pre-audit path** before the next AUDIT).
|
|
205
|
+
3. **FIX** (`last_action == "audited"` and `last_findings.total > 0`): `loop_count += 1`; if `loop_count > 10` → `cap reached`; **FIX** (bugfix); print `Loop <N> fix: ...`; `last_action = "fixed"`, update `audit_log`; loop to step 1.
|
|
257
206
|
|
|
258
|
-
4. After **AUDIT
|
|
207
|
+
4. After **AUDIT**: update `last_action`, `last_findings`, `audit_log`; print audit line if not already printed.
|
|
259
208
|
|
|
260
209
|
5. Loop.
|
|
261
210
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
### AUDIT action (clean-room teammate, fresh per loop)
|
|
211
|
+
First pass: pre-audit → AUDIT. After a FIX, the next pass runs pre-audit again before the next AUDIT.
|
|
265
212
|
|
|
266
|
-
|
|
213
|
+
### AUDIT action
|
|
267
214
|
|
|
268
|
-
```
|
|
215
|
+
```bash
|
|
269
216
|
mkdir -p "<team_temp_dir>"
|
|
270
217
|
gh pr diff <number> -R <owner>/<repo> > "<team_temp_dir>/loop-<N>.patch"
|
|
271
218
|
```
|
|
272
219
|
|
|
273
|
-
`<team_temp_dir>` is the absolute path captured in Step 2 (already includes the sanitized team_name and timestamp suffix, and `team_name` itself is already prefixed with `bugteam-`). Claude resolves the portable temp root once via `Path(tempfile.gettempdir()) / team_name` (requires `import tempfile`) and passes the literal absolute path to every shell command. `tempfile.gettempdir()` honors `TMPDIR`, `TEMP`, and `TMP` in the platform-correct order and falls back to `C:\Users\<user>\AppData\Local\Temp` on Windows or `/tmp` on Unix, so this works identically on macOS, Linux, Windows cmd.exe, and PowerShell: Claude resolves the literal path once and every shell receives the same absolute value.
|
|
274
|
-
|
|
275
|
-
Spawn a fresh `bugfind` teammate for this loop by calling the `Agent` tool with these exact arguments:
|
|
276
|
-
|
|
277
220
|
```
|
|
278
221
|
Agent(
|
|
279
222
|
subagent_type="code-quality-agent",
|
|
@@ -281,60 +224,28 @@ Agent(
|
|
|
281
224
|
team_name="<team_name>",
|
|
282
225
|
model="sonnet",
|
|
283
226
|
description="Bugfind audit loop <N>",
|
|
284
|
-
prompt="<audit XML
|
|
227
|
+
prompt="<audit XML; see PROMPTS.md>"
|
|
285
228
|
)
|
|
286
229
|
```
|
|
287
230
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
See [`PROMPTS.md`](PROMPTS.md) for the AUDIT spawn-prompt XML and bugfind outcome schema. Substitute placeholders (repo, branch, base_branch, pr_url, loop, diff_path) and pass the result as the `prompt` argument.
|
|
231
|
+
Fresh `Agent` each loop; teammate context excludes lead history ([`sources.md`](sources.md) § Teammate context isolation). [`PROMPTS.md`](PROMPTS.md): XML + outcome schema. Lead reads `.bugteam-loop-<N>.outcomes.xml`, fills `loop_comment_index`.
|
|
291
232
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
**Expected path: self-termination.** In practice, teammates self-terminate when their task is complete — the `Agent` call returns and the teammate's session ends automatically. When that happens, no `SendMessage` shutdown is needed and the cycle proceeds directly to the next action.
|
|
295
|
-
|
|
296
|
-
**Fallback path: lead-initiated shutdown.** If the teammate has not self-terminated after the `Agent` call returns (observable as the teammate still appearing in the active-teammates list), send a shutdown message:
|
|
233
|
+
**Shutdown:** If `Agent` returned and the teammate already ended, skip. Otherwise:
|
|
297
234
|
|
|
298
235
|
```
|
|
299
236
|
SendMessage(
|
|
300
237
|
to="bugfind",
|
|
301
|
-
message={
|
|
302
|
-
"type": "shutdown_request",
|
|
303
|
-
"reason": "audit loop <N> complete; outcome XML captured"
|
|
304
|
-
}
|
|
238
|
+
message={"type": "shutdown_request", "reason": "audit loop <N> complete; outcome XML captured"}
|
|
305
239
|
)
|
|
306
240
|
```
|
|
307
241
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
`last_action = "audited"`. `last_findings = parsed`. Append `(loop=N, action="audit", counts={P0,P1,P2}, sha=current_HEAD, review_url=<url>, finding_count=<n>, fallback_count=<n>)` to `audit_log`.
|
|
311
|
-
|
|
312
|
-
**Parallel auditors from loop 4 onward (`loop_count >= 4`).** The pre-audit code rules gate must still pass immediately before this step (Step 3). After three full audit/fix rounds without convergence, spawn three bugfind teammates concurrently by issuing three `Agent` calls in a single assistant message so they run in parallel:
|
|
313
|
-
|
|
314
|
-
```
|
|
315
|
-
Agent(subagent_type="code-quality-agent", name="bugfind-loop-<N>-a", team_name="<team_name>", model="sonnet", description="Bugfind audit loop <N> variant a", prompt="<audit XML; write outcome to .bugteam-loop-<N>.outcomes.xml; post the per-loop review; read and merge b/c outcomes from <team_temp_dir>/loop-<N>-b.outcomes.xml and <team_temp_dir>/loop-<N>-c.outcomes.xml>")
|
|
316
|
-
Agent(subagent_type="code-quality-agent", name="bugfind-loop-<N>-b", team_name="<team_name>", model="sonnet", description="Bugfind audit loop <N> variant b", prompt="<audit XML; write outcome to <team_temp_dir>/loop-<N>-b.outcomes.xml; skip PR posting>")
|
|
317
|
-
Agent(subagent_type="code-quality-agent", name="bugfind-loop-<N>-c", team_name="<team_name>", model="sonnet", description="Bugfind audit loop <N> variant c", prompt="<audit XML; write outcome to <team_temp_dir>/loop-<N>-c.outcomes.xml; skip PR posting>")
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
Teammate `-a` is the post-owner: it reads all three outcome XML files using their explicit absolute paths — its own outcome at `.bugteam-loop-<N>.outcomes.xml` (working directory), and the sibling outcomes at `<team_temp_dir>/loop-<N>-b.outcomes.xml` and `<team_temp_dir>/loop-<N>-c.outcomes.xml` — then merges findings by `(file, line, category_letter)` (same tuple collapses to one finding, keeping the longest description and the highest severity of the group), re-assigns merged-finding IDs as `loopN-K`, and posts the single per-loop review per the standard posting protocol above. The `-a` spawn prompt must include both sibling paths as literal absolute values so `-a` can read them with the `Read` tool by path without any discovery step.
|
|
242
|
+
`approve: false` → `error: bugfind teammate refused shutdown` → Step 4 then 5.
|
|
321
243
|
|
|
322
|
-
|
|
244
|
+
`last_action = "audited"`; append audit line to `audit_log`.
|
|
323
245
|
|
|
324
|
-
|
|
325
|
-
SendMessage(to="bugfind-loop-<N>-b", message={"type": "shutdown_request", "reason": "variant XML captured"})
|
|
326
|
-
SendMessage(to="bugfind-loop-<N>-c", message={"type": "shutdown_request", "reason": "variant XML captured"})
|
|
327
|
-
```
|
|
246
|
+
**Parallel auditors (`loop_count >= 4`):** gate passes immediately before; after three full audit/fix rounds without convergence, issue three `Agent` calls in one assistant message (parallel). `-a` posts the review and merges outcomes from `-b`/`-c` (read `.bugteam-loop-<N>.outcomes.xml` plus `<team_temp_dir>/loop-<N>-b.outcomes.xml` and `...-c...`); merge key `(file, line, category_letter)`; re-id `loopN-K`. `-b`/`-c` write sibling XML only; prompts must pass literal absolute sibling paths. Shutdown: parallel `SendMessage` to `b` and `c`, then `a`.
|
|
328
247
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
```
|
|
332
|
-
SendMessage(to="bugfind-loop-<N>-a", message={"type": "shutdown_request", "reason": "merged review posted"})
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
### FIX action (fresh teammate, only sees latest audit)
|
|
336
|
-
|
|
337
|
-
Spawn a fresh `bugfix` teammate for this loop by calling the `Agent` tool with these exact arguments:
|
|
248
|
+
### FIX action
|
|
338
249
|
|
|
339
250
|
```
|
|
340
251
|
Agent(
|
|
@@ -343,127 +254,45 @@ Agent(
|
|
|
343
254
|
team_name="<team_name>",
|
|
344
255
|
model="sonnet",
|
|
345
256
|
description="Bugfix loop <N>",
|
|
346
|
-
prompt="<fix XML
|
|
257
|
+
prompt="<fix XML; see PROMPTS.md>"
|
|
347
258
|
)
|
|
348
259
|
```
|
|
349
260
|
|
|
350
|
-
|
|
261
|
+
Pass finding comment URLs/ids from `loop_comment_index` in XML. Replies: `Fixed in <sha>` or `Could not address this loop: <reason>`.
|
|
351
262
|
|
|
352
|
-
|
|
263
|
+
**Shutdown:** same as bugfind; else `SendMessage(to="bugfix", message={"type": "shutdown_request", "reason": "fix loop <N> complete; commit <sha7> pushed"})`. `approve: false` → `error: bugfix teammate refused shutdown` → Step 4 then 5.
|
|
353
264
|
|
|
354
|
-
|
|
265
|
+
[`PROMPTS.md`](PROMPTS.md): fix XML + schema. Verify: `git rev-parse HEAD` advanced; `git fetch origin <branch> && git rev-parse origin/<branch>` matches `HEAD`. Unchanged HEAD → `stuck — bugfix teammate could not address findings`.
|
|
355
266
|
|
|
356
|
-
|
|
267
|
+
### Step 4: Teardown
|
|
357
268
|
|
|
358
|
-
|
|
269
|
+
1. For each live teammate: `SendMessage(to="<name>", message={"type": "shutdown_request", "reason": "bugteam cycle ending"})`. `approve: false` on cleanup → log and continue.
|
|
359
270
|
|
|
360
|
-
|
|
361
|
-
SendMessage(
|
|
362
|
-
to="bugfix",
|
|
363
|
-
message={
|
|
364
|
-
"type": "shutdown_request",
|
|
365
|
-
"reason": "fix loop <N> complete; commit <sha7> pushed"
|
|
366
|
-
}
|
|
367
|
-
)
|
|
368
|
-
```
|
|
271
|
+
2. `TeamDelete()`
|
|
369
272
|
|
|
370
|
-
|
|
273
|
+
3. `python -c "import shutil; shutil.rmtree(r'<team_temp_dir>', ignore_errors=True)"`
|
|
371
274
|
|
|
372
|
-
|
|
275
|
+
### Step 4.5: PR description
|
|
373
276
|
|
|
374
|
-
|
|
277
|
+
Lead only; cumulative product narrative (not process). Delegate body to `pr-description-writer` via `Agent` (else `general-purpose`) so the mandatory-pr-description hook accepts `gh pr edit`.
|
|
375
278
|
|
|
376
|
-
|
|
377
|
-
|
|
279
|
+
1. `gh pr diff <number> -R <owner>/<repo> > .bugteam-final.diff`
|
|
280
|
+
2. `gh pr view <number> -R <owner>/<repo> --json body --jq .body > .bugteam-original-body.md`
|
|
281
|
+
3. Agent brief: paths + branch names; describe merge-ready change from diff; keep curated original sections intact; return markdown body.
|
|
282
|
+
4. Write `.bugteam-final-body.md`; `gh pr edit <number> -R <owner>/<repo> --body-file .bugteam-final-body.md`
|
|
283
|
+
5. Delete the three temp files.
|
|
378
284
|
|
|
379
|
-
|
|
285
|
+
On failure: log in final report; continue to Step 5.
|
|
380
286
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
### Step 4: Tear down the team and clean working tree
|
|
384
|
-
|
|
385
|
-
When the cycle exits (any reason), run these steps in order from THIS session (the lead):
|
|
386
|
-
|
|
387
|
-
1. **Confirm every teammate has shut down.** Any teammate still alive (for example, from an aborted shutdown mid-loop) must receive a shutdown message first. For each remaining teammate name:
|
|
388
|
-
|
|
389
|
-
```
|
|
390
|
-
SendMessage(to="<teammate_name>", message={"type": "shutdown_request", "reason": "bugteam cycle ending"})
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
The docs state: *"When the lead runs cleanup, it checks for active teammates and fails if any are still running, so shut them down first."*
|
|
394
|
-
|
|
395
|
-
If any teammate returns `approve: false` during this cleanup shutdown, log the refusing teammate name (e.g., `cleanup warning: <teammate_name> refused shutdown_request`) and force-proceed to step 2 (`TeamDelete`) anyway. `TeamDelete` may fail if active teammates remain; if it does, surface the error in the final report with the refusing teammate name so the user can manually clean up. Do not abort the cleanup sequence — continue through temp-dir deletion, Step 4.5, and Step 5 regardless.
|
|
396
|
-
|
|
397
|
-
2. **Clean up the team** by calling `TeamDelete` with no arguments — it reads `<team_name>` from the current session's team context:
|
|
398
|
-
|
|
399
|
-
```
|
|
400
|
-
TeamDelete()
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
The docs state: *"When you're done, ask the lead to clean up: 'Clean up the team'."* `TeamDelete` is the tool that resolves that sentence.
|
|
404
|
-
|
|
405
|
-
3. **Delete the per-team scoped temp directory** by running this Python one-liner through the `Bash` tool (same literal `<team_temp_dir>` path resolved at Step 2):
|
|
406
|
-
|
|
407
|
-
```
|
|
408
|
-
python -c "import shutil; shutil.rmtree(r'<team_temp_dir>', ignore_errors=True)"
|
|
409
|
-
```
|
|
410
|
-
|
|
411
|
-
`shutil.rmtree(..., ignore_errors=True)` works identically on Windows and Unix, so the lead uses one command regardless of platform.
|
|
412
|
-
|
|
413
|
-
### Step 4.5: Finalize the PR description (mandatory)
|
|
414
|
-
|
|
415
|
-
After teardown and before permission revoke, the lead rewrites the PR body to reflect the PR's **final cumulative state** — the change the PR delivers, not the bugteam process. This is the **only** PR-write the lead performs (audit and fix comments belong to the teammates).
|
|
416
|
-
|
|
417
|
-
The lead delegates the body authoring to the `pr-description-writer` agent so the global mandatory-pr-description-writer hook accepts the subsequent `gh pr edit`. The lead does NOT compose the body inline.
|
|
418
|
-
|
|
419
|
-
`pr-description-writer` is provided by the global git-workflow rule in `claude-code-config`. Invoke it with the `Agent` tool:
|
|
420
|
-
|
|
421
|
-
```
|
|
422
|
-
Agent(
|
|
423
|
-
subagent_type="pr-description-writer",
|
|
424
|
-
description="Rewrite PR <number> body from cumulative diff",
|
|
425
|
-
prompt="<brief from step 3 below>"
|
|
426
|
-
)
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
If `pr-description-writer` is not in the available agents list for the current environment, fall back to `general-purpose` with the same brief — the global hook treats agent-authored bodies the same regardless of the specific agent type:
|
|
430
|
-
|
|
431
|
-
```
|
|
432
|
-
Agent(
|
|
433
|
-
subagent_type="general-purpose",
|
|
434
|
-
description="Rewrite PR <number> body from cumulative diff",
|
|
435
|
-
prompt="<brief from step 3 below>"
|
|
436
|
-
)
|
|
437
|
-
```
|
|
438
|
-
|
|
439
|
-
When neither agent is available, log a warning in the final report and skip Step 4.5 so the original PR body stays in place.
|
|
440
|
-
|
|
441
|
-
Steps:
|
|
442
|
-
|
|
443
|
-
1. Capture the cumulative diff: `gh pr diff <number> -R <owner>/<repo> > .bugteam-final.diff`.
|
|
444
|
-
2. Capture the original body: `gh pr view <number> -R <owner>/<repo> --json body --jq .body > .bugteam-original-body.md`.
|
|
445
|
-
3. Invoke the `pr-description-writer` agent (or `general-purpose` fallback) with this brief:
|
|
446
|
-
- **Inputs:** the diff path, the original body path, the head branch name, the base branch name.
|
|
447
|
-
- **Constraint:** describe what the PR delivers based on the cumulative diff — code behavior, user-facing effect, and merge rationale. Process metadata (audit loops, fix commit counts, finding counts) lives in the finding comments. The description speaks to the merge audience.
|
|
448
|
-
- **Preservation rule:** if the original body contains sections that look manually curated (linked issues, screenshots, a populated test plan, "Risk Assessment" sections), preserve those verbatim and only rewrite the prose narrative around them.
|
|
449
|
-
- **Output:** the new body markdown.
|
|
450
|
-
4. Write the agent's returned body to `.bugteam-final-body.md`.
|
|
451
|
-
5. Apply: `gh pr edit <number> -R <owner>/<repo> --body-file .bugteam-final-body.md`.
|
|
452
|
-
6. Delete `.bugteam-final.diff`, `.bugteam-original-body.md`, and `.bugteam-final-body.md`.
|
|
453
|
-
|
|
454
|
-
If Step 4.5 fails for any reason (agent error, hook block, network), surface the failure in the final report and continue to Step 5. The original PR body remains; the rest of the cycle's work (commits, comments, replies) is unaffected.
|
|
455
|
-
|
|
456
|
-
### Step 5: Revoke project permissions (mandatory, runs always)
|
|
457
|
-
|
|
458
|
-
After team cleanup completes — including on error, cap-reached, or stuck exits — run:
|
|
287
|
+
### Step 5: Revoke permissions (always)
|
|
459
288
|
|
|
460
289
|
```bash
|
|
461
|
-
python "${CLAUDE_SKILL_DIR}/revoke_project_claude_permissions.py"
|
|
290
|
+
python "${CLAUDE_SKILL_DIR}/scripts/revoke_project_claude_permissions.py"
|
|
462
291
|
```
|
|
463
292
|
|
|
464
|
-
|
|
293
|
+
Removes Step 0 grant — run even if Step 4 partially failed (log separately).
|
|
465
294
|
|
|
466
|
-
### Step 6:
|
|
295
|
+
### Step 6: Final report
|
|
467
296
|
|
|
468
297
|
```
|
|
469
298
|
/bugteam exit: <converged | cap reached | stuck | error>
|
|
@@ -474,13 +303,10 @@ Net change: <total_files> files, +<total_add>/-<total_del>
|
|
|
474
303
|
|
|
475
304
|
Loop log:
|
|
476
305
|
1 audit: 3P0 2P1 0P2
|
|
477
|
-
|
|
478
|
-
2 audit: 1P0 0P1 0P2
|
|
479
|
-
2 fix: commit e4f5g6h (1 file, +2/-1)
|
|
480
|
-
3 audit: 0P0 0P1 0P2 → converged
|
|
306
|
+
...
|
|
481
307
|
```
|
|
482
308
|
|
|
483
|
-
|
|
309
|
+
`cap reached` → suggest `/findbugs`. `stuck` → which findings. `error` → detail + loop.
|
|
484
310
|
|
|
485
311
|
## Constraints
|
|
486
312
|
|
|
@@ -489,3 +315,11 @@ See [`CONSTRAINTS.md`](CONSTRAINTS.md).
|
|
|
489
315
|
## Examples
|
|
490
316
|
|
|
491
317
|
See [`EXAMPLES.md`](EXAMPLES.md).
|
|
318
|
+
|
|
319
|
+
## Reference
|
|
320
|
+
|
|
321
|
+
See [`reference/README.md`](reference/README.md).
|
|
322
|
+
|
|
323
|
+
## Sources
|
|
324
|
+
|
|
325
|
+
See [`sources.md`](sources.md).
|