@iceinvein/agent-skills 0.1.38 → 0.1.39
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/package.json +1 -1
- package/skills/index.json +1 -1
- package/skills/magpie/README.md +2 -1
- package/skills/magpie/SKILL.md +29 -530
- package/skills/magpie/package.json +1 -1
- package/skills/magpie/references/critic.md +58 -0
- package/skills/magpie/references/peer-review.md +84 -0
- package/skills/magpie/references/specialists.md +391 -0
- package/skills/magpie/scripts/__tests__/helper.test.ts +40 -0
- package/skills/magpie/scripts/__tests__/skill-lint.test.ts +116 -28
- package/skills/magpie/scripts/__tests__/status-cmd.test.ts +13 -0
- package/skills/magpie/scripts/helper.js +24 -13
- package/skills/magpie/scripts/status-cmd.ts +10 -1
- package/skills/magpie/skill.json +2 -1
package/skills/magpie/SKILL.md
CHANGED
|
@@ -17,7 +17,15 @@ Stop reading and follow these steps in order. Do not skip stages. Use the exact
|
|
|
17
17
|
|
|
18
18
|
Parse the user's request for a PR number, URL, or "this PR" (current branch). If ambiguous, ask one clarifying terminal question. Capture the PR number into `$PR_NUMBER` and the repository path into `$REPO` (default: current working directory).
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Then check whether an earlier run on this PR is still unfinished, before minting a new id:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
magpie --list-runs
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Each line is `<id>\t<active|archived>\t<path>`. If an `active` id matches `pr-${PR_NUMBER}-*`, that run was interrupted rather than cleaned up. Set `RUN_DIR` to its path and go to "Resuming a crashed run" instead of starting over; ask the user first if it is unclear whether they want to resume or review from scratch. (`archived` ids are finished runs, not resumable.)
|
|
27
|
+
|
|
28
|
+
Otherwise compute a fresh run directory:
|
|
21
29
|
|
|
22
30
|
```
|
|
23
31
|
RUN_ID="pr-${PR_NUMBER}-$(date +%s)"
|
|
@@ -38,7 +46,7 @@ When a prior run exists for the same PR (active or archived under `~/.magpie/`),
|
|
|
38
46
|
|
|
39
47
|
Setup also runs a deterministic test-coverage check: when the diff contains zero test or spec files anywhere, each non-test source file with `>= 10` added code lines gets a `domain: "tests"` finding written to `$RUN_DIR/findings/tests.json`. This is a sixth domain that flows through dedupe/critic/peer-review alongside the five LLM specialists. No specialist subagent is dispatched for it.
|
|
40
48
|
|
|
41
|
-
The pipeline has no separate context-indexing stage, but `magpie status` and the progress page track one. After setup succeeds, append `{stage: context, status: skipped}` to `$RUN_DIR/log.jsonl
|
|
49
|
+
The pipeline has no separate context-indexing stage, but `magpie status` and the progress page track one. After setup succeeds, append `{stage: context, status: skipped}` to `$RUN_DIR/log.jsonl`; both treat a skipped stage as behind them, so the pipeline advances to `specialists`.
|
|
42
50
|
|
|
43
51
|
### 2. Serve
|
|
44
52
|
|
|
@@ -50,6 +58,8 @@ magpie serve "$RUN_DIR"
|
|
|
50
58
|
|
|
51
59
|
Read `$RUN_DIR/state/server-info` for the URL; the server writes it asynchronously at startup, so if the file doesn't exist yet, wait a moment and re-read (it appears within ~1s). Print to the user: "Open <url> in your browser to follow along."
|
|
52
60
|
|
|
61
|
+
The server shuts down after 30 minutes with no requests (an open report tab heartbeats every 30s, so it stays up while the user is looking at it) and deletes `state/server-info` on the way out. Nothing in the pipeline depends on it staying alive: re-run `magpie serve "$RUN_DIR"` to bring the report back.
|
|
62
|
+
|
|
53
63
|
Render the first progress paint:
|
|
54
64
|
|
|
55
65
|
```
|
|
@@ -58,75 +68,9 @@ magpie render "$RUN_DIR" progress
|
|
|
58
68
|
|
|
59
69
|
### 3. Specialists
|
|
60
70
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
````
|
|
64
|
-
<specialist block for focus from this SKILL.md>
|
|
65
|
-
|
|
66
|
-
You are reviewing PR #<PR_NUMBER>.
|
|
67
|
-
Working directory: $RUN_DIR/worktree
|
|
68
|
-
Diff: $RUN_DIR/diff.patch
|
|
69
|
-
|
|
70
|
-
## Output Contract
|
|
71
|
-
|
|
72
|
-
Write findings to $RUN_DIR/findings/<focus>.json before returning. The file MUST be a JSON array. Each entry MUST conform to this schema exactly (no extra top-level keys, no renamed keys):
|
|
73
|
-
|
|
74
|
-
{
|
|
75
|
-
"id": string, // e.g. "<focus>-1", "<focus>-2"; unique per focus
|
|
76
|
-
"file": string, // path relative to worktree
|
|
77
|
-
"line": number | null, // single integer; use null if not anchorable. NOT "lines", NOT a range string
|
|
78
|
-
"severity": "blocker" | "high" | "medium" | "low",
|
|
79
|
-
"risk": { // OBJECT, not a flat string
|
|
80
|
-
"impact": "critical" | "high" | "medium" | "low",
|
|
81
|
-
"likelihood": "likely" | "possible" | "edge-case" | "unknown",
|
|
82
|
-
"confidence": "high" | "medium" | "low",
|
|
83
|
-
"action": "must-fix" | "should-fix" | "consider" | "optional"
|
|
84
|
-
},
|
|
85
|
-
"title": string, // one line
|
|
86
|
-
"description": string, // 2-4 short labelled paragraphs (see below). Cite code with file:line.
|
|
87
|
-
"suggestion": { // OPTIONAL; omit the key entirely if not applicable. NOT "recommendation"
|
|
88
|
-
"body": string, // LITERAL replacement source code for lines startLine..endLine. NOT prose. See rules below.
|
|
89
|
-
"startLine": number,
|
|
90
|
-
"endLine": number
|
|
91
|
-
},
|
|
92
|
-
"domain": "<focus>" // literal focus id, copied verbatim
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
**Enum values are exact strings, not free-form prose.** Every value above between `"..."` and `|` markers is a literal token. Copy them verbatim. Specifically:
|
|
96
|
-
|
|
97
|
-
- `severity`, `risk.impact`, `risk.confidence` use category names (e.g. `high`, `low`), not sentences.
|
|
98
|
-
- `risk.likelihood` describes frequency, not impact. Valid values are exactly `likely`, `possible`, `edge-case`, `unknown`. NEVER use `high`/`medium`/`low` here (those are likelihood-as-impact and will be auto-corrected, but pick the right axis).
|
|
99
|
-
- `risk.action` is the disposition tag, not the recommendation text. Valid values are exactly `must-fix`, `should-fix`, `consider`, `optional`. The recommendation prose belongs in `description` under `Suggested direction:`, never in `risk.action`.
|
|
100
|
-
- Keep `severity` coherent with `risk`. `severity` is the headline label: use `blocker`/`high` only with `risk.impact` of `critical`/`high` and `risk.action` of `must-fix`/`should-fix`. A `low` severity paired with `must-fix`, or a `blocker` paired with `optional`, is contradictory. The 0-10 score that gates the drop threshold is derived from `risk`, not from `severity`, so an inflated `severity` on a weak `risk` is still dropped. Set `risk` accurately rather than leaning on `severity`.
|
|
101
|
-
|
|
102
|
-
Bad (will be silently coerced, do not rely on this):
|
|
103
|
-
```
|
|
104
|
-
"risk": { "impact": "blocker", "likelihood": "high", "confidence": "very high", "action": "Fix this immediately before merging." }
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
Good:
|
|
108
|
-
```
|
|
109
|
-
"risk": { "impact": "critical", "likelihood": "likely", "confidence": "high", "action": "must-fix" }
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
`description` MUST be a sequence of short labelled paragraphs separated by blank lines, using these exact prefixes when they apply:
|
|
113
|
-
|
|
114
|
-
- `Observation: <one idea, what the diff actually does and where>`
|
|
115
|
-
- `Why it matters: <impact at realistic scale or on a real user path>`
|
|
116
|
-
- `Suggested direction: <one concrete next step, optional if the fix isn't obvious>`
|
|
117
|
-
- `Needs verification: <what you couldn't confirm from the bundle, optional, low/medium severity only>` This labelled paragraph is the only channel for uncertainty: never hedge inside another section, and never raise `severity` to compensate for what you couldn't verify (a blocker/high you cannot stand behind is not a blocker/high). Use the exact `Needs verification:` prefix, not inline phrasing.
|
|
118
|
-
|
|
119
|
-
One idea per paragraph. Do not collapse them into a single wall of text. Do not invent extra labels. If a section doesn't apply, omit it. The interactive report and the GitHub comment both parse these labels and render them as section headers, so missing labels degrade the output.
|
|
120
|
-
|
|
121
|
-
**`suggestion.body` rules.** When present, `body` MUST be the literal source code that should replace lines `startLine..endLine` verbatim. It is fenced as `` ```suggestion `` on GitHub and rendered as a one-click "Apply" button; the bytes you write here get committed as-is to the PR. Therefore:
|
|
122
|
-
|
|
123
|
-
- Write code only. No leading "Strip the delimiter...", "Add a check that...", or other prose. The prose explanation belongs in `description` under `Suggested direction:`.
|
|
124
|
-
- Match the file's existing indentation and language exactly. Include only the lines being replaced; do not include unchanged surrounding context.
|
|
125
|
-
- If you cannot produce an exact, copy-pasteable replacement (you don't know the surrounding code, the fix spans multiple files, or the change is conceptual), OMIT the `suggestion` key entirely. A prose `Suggested direction:` in `description` is the right channel for that.
|
|
126
|
-
- Wrapping the code in a `` ``` `` fence inside `body` is tolerated (the poster hoists the inner code out), but bare code is preferred.
|
|
71
|
+
Read `references/specialists.md` now, before dispatching anything. It holds the five focus blocks and the output contract that every specialist prompt is built from. Assemble the prompts from that file verbatim: prompts written from memory drift off the JSON contract, and `magpie dedupe` drops findings it cannot parse.
|
|
127
72
|
|
|
128
|
-
|
|
129
|
-
````
|
|
73
|
+
Append `{stage: specialists, status: running}` to `$RUN_DIR/log.jsonl` and re-render progress, so the served page shows the stage as active rather than "Paused". Then dispatch the five specialist subagents in a single message using five Agent tool calls in parallel, one per focus in (security, bugs, performance, code-smells, architecture), each carrying the prompt that `references/specialists.md` describes.
|
|
130
74
|
|
|
131
75
|
After each subagent returns, append `{stage: specialist, focus: <focus>, status: done, findings: <count>}` to `$RUN_DIR/log.jsonl` and re-render progress. (Per-focus `specialist` entries are diagnostic; only the aggregate `specialists` entry advances `magpie status`.)
|
|
132
76
|
|
|
@@ -146,13 +90,13 @@ Re-render progress.
|
|
|
146
90
|
|
|
147
91
|
### 5. Critic
|
|
148
92
|
|
|
149
|
-
Read `$RUN_DIR/findings.deduped.json`. Substitute both placeholders in the critic rubric (the compact candidate list including each finding's `onChangedLine`, and the `<<DIFF_EXCERPT>>` hunks for the referenced files), then apply the rubric verbatim (one verdict per finding). Write the kept subset to `$RUN_DIR/findings.kept.json`. Append `{stage: critic, status: done}` and re-render progress.
|
|
93
|
+
Read `references/critic.md` and `$RUN_DIR/findings.deduped.json`. Substitute both placeholders in the critic rubric (the compact candidate list including each finding's `onChangedLine`, and the `<<DIFF_EXCERPT>>` hunks for the referenced files), then apply the rubric verbatim (one verdict per finding). Write the kept subset to `$RUN_DIR/findings.kept.json`. Append `{stage: critic, status: done}` and re-render progress.
|
|
150
94
|
|
|
151
95
|
### 6. Peer review
|
|
152
96
|
|
|
153
97
|
Append `{stage: peer-review, status: running}` to `$RUN_DIR/log.jsonl` and re-render progress. This stage always runs. `codex` is the preferred reviewer because it is a different model from the Claude agents that produced the findings; when `codex` is unavailable, a Claude second-opinion subagent stands in.
|
|
154
98
|
|
|
155
|
-
Build the peer-review prompt first: take the `magpie-peer-review` block from
|
|
99
|
+
Build the peer-review prompt first: read `references/peer-review.md`, take the `magpie-peer-review` block from it, and substitute the placeholders listed in that file's `## Substitute before use` preamble. Write the substituted prompt to `$RUN_DIR/peer-prompt.md`.
|
|
156
100
|
|
|
157
101
|
**Codex path (preferred).** If `codex` is available (setup did not log `missingOptional: ["codex"]` and `command -v codex` succeeds), set `<<PEER_PROVIDER>>` to `codex` and run codex with the prompt piped on stdin:
|
|
158
102
|
|
|
@@ -164,7 +108,7 @@ codex exec < "$RUN_DIR/peer-prompt.md" > "$RUN_DIR/peer.out"
|
|
|
164
108
|
|
|
165
109
|
If codex returns non-zero, do not abort: record `{stage: peer-review, provider: codex, status: fallback, error: "<first line of stderr>"}` and fall through to the Claude path. (Never log `status: error` for a recoverable codex failure: `magpie status` stops at the first `error` entry and would report the run as poisoned even after the Claude fallback succeeds.)
|
|
166
110
|
|
|
167
|
-
**Claude path (fallback).** When `codex` is unavailable or failed, get the second opinion from a Claude subagent instead. Set `<<PEER_PROVIDER>>` to `claude`, then prepend the `magpie-peer-review-claude-preamble` block from
|
|
111
|
+
**Claude path (fallback).** When `codex` is unavailable or failed, get the second opinion from a Claude subagent instead. Set `<<PEER_PROVIDER>>` to `claude`, then prepend the `magpie-peer-review-claude-preamble` block from `references/peer-review.md` to the substituted peer-review prompt (the preamble forces genuine independence, since the reviewer shares a model family with the primary reviewers). Dispatch one subagent (Agent tool, `general-purpose`) whose entire task is that combined prompt, and instruct it to return only the fenced `review-peer-review` JSON block. Write its output to `$RUN_DIR/peer.out`, extract the `review-peer-review` block to `$RUN_DIR/peer.json`, and append `{stage: peer-review, status: done, provider: claude}`.
|
|
168
112
|
|
|
169
113
|
**Apply the verdicts (both paths).** Parse the verdicts JSON and apply the `update` / `add` entries (an empty array means no change). For each `add`, mint a unique `id` on the new finding before merging (`peer-1`, `peer-2`, ...): the peer contract does not include ids, but every finding in `findings.final.json` must carry one or the report render and post stages will crash. Then write `findings.final.json`. Re-render progress.
|
|
170
114
|
|
|
@@ -176,15 +120,15 @@ magpie render "$RUN_DIR" findings
|
|
|
176
120
|
|
|
177
121
|
Append `{stage: report, status: done}` to `$RUN_DIR/log.jsonl` and re-render progress (the render CLI does not log this itself, and `magpie status` needs the `done` entry to resume past `report`).
|
|
178
122
|
|
|
179
|
-
Print to the terminal: "Findings ready at <url>.
|
|
123
|
+
Print to the terminal: "Findings ready at <url>. Tick the ones you want and click **Post Selected**, or reply `post` here and I'll post whatever you've ticked."
|
|
180
124
|
|
|
181
125
|
End the turn.
|
|
182
126
|
|
|
183
127
|
### 8. Post
|
|
184
128
|
|
|
185
|
-
Most users will tick the checkboxes in the served report and click
|
|
129
|
+
Most users will tick the checkboxes in the served report and click **Post Selected** (or **Post Recommended**, which takes every finding whose `risk.action` is `must-fix` or `should-fix`, skipping the `consider`/`optional` ones); the report server handles the rest and posts the batch as one GitHub review with inline threads. The agent only handles posts when the user explicitly types `post` (optionally `post 1,3,7` for indices) in the conversation, which takes the CLI path below: separate inline comments plus a top-level summary comment. Either path records posted ids in `post-status.json`, so the two cannot double-post the same finding.
|
|
186
130
|
|
|
187
|
-
When
|
|
131
|
+
When the user types `post`, read `$RUN_DIR/state/events`. Fold the events in order, keeping the LAST event per finding id; ids whose last event is `select` are selected. (Not union-minus: the UI emits one event per toggle, so select then deselect then select again must resolve to selected.) Merge with any explicit indices the user named (1-based, against `findings.final.json` in file order). If that leaves nothing selected, say so and ask rather than posting an empty batch. Then post via the CLI:
|
|
188
132
|
|
|
189
133
|
```
|
|
190
134
|
magpie post "$RUN_DIR" --ids id1,id2,id3
|
|
@@ -218,467 +162,22 @@ The archived `findings.html` is self-contained and auto-switches to read-only "a
|
|
|
218
162
|
- `magpie serve <id>` re-spins the Bun server against an archived run if the user wants the live interactive surface back (posts still work because `pr.json` retains the head SHA).
|
|
219
163
|
- `magpie --list-runs` enumerates all runs in `~/.magpie/`.
|
|
220
164
|
|
|
221
|
-
## Specialist prompts
|
|
222
|
-
|
|
223
|
-
### security
|
|
224
|
-
|
|
225
|
-
```magpie-specialist-security
|
|
226
|
-
You are a senior application security engineer reviewing this pull request.
|
|
227
|
-
|
|
228
|
-
## What to look for
|
|
229
|
-
|
|
230
|
-
Inspect every changed line for these vulnerability classes:
|
|
231
|
-
|
|
232
|
-
**Injection attacks**
|
|
233
|
-
- SQL injection: string concatenation in queries, missing parameterized statements
|
|
234
|
-
- Command injection: user input flowing into shell commands, execFile(), spawn()
|
|
235
|
-
- Template injection: unsanitized data in template engines
|
|
236
|
-
- XSS: unescaped output in HTML/JSX, unsafe innerHTML usage, React dangerouslySetInnerHTML
|
|
237
|
-
- Path traversal: user-controlled file paths without canonicalization or allowlist
|
|
238
|
-
- SSRF: user-controlled URLs passed to fetch/http requests without validation
|
|
239
|
-
- Deserialization: untrusted data passed to JSON.parse in security-sensitive contexts
|
|
240
|
-
|
|
241
|
-
**Authentication & authorization**
|
|
242
|
-
- Missing auth checks on new endpoints or IPC handlers
|
|
243
|
-
- Privilege escalation: actions that bypass permission boundaries
|
|
244
|
-
- Broken access control: one user accessing another's resources
|
|
245
|
-
- Session management issues: predictable tokens, missing expiry, no invalidation
|
|
246
|
-
- Tenant isolation violations in multi-user contexts
|
|
247
|
-
|
|
248
|
-
**Secrets & credentials**
|
|
249
|
-
- Hardcoded API keys, tokens, passwords, or connection strings
|
|
250
|
-
- Secrets logged to console or persisted in plaintext
|
|
251
|
-
- Credentials in URLs or query parameters
|
|
252
|
-
- Missing encryption for sensitive data at rest or in transit
|
|
253
|
-
|
|
254
|
-
**Cryptography**
|
|
255
|
-
- Weak algorithms (MD5, SHA1 for security purposes, DES)
|
|
256
|
-
- Missing or predictable IVs/nonces
|
|
257
|
-
- Custom crypto implementations instead of vetted libraries
|
|
258
|
-
- Insufficient key lengths
|
|
259
|
-
|
|
260
|
-
**Data safety**
|
|
261
|
-
- Sensitive data in error messages or logs (PII, tokens, passwords)
|
|
262
|
-
- Missing input validation at system boundaries (user input, external APIs, IPC)
|
|
263
|
-
- Missing output encoding when crossing trust boundaries
|
|
264
|
-
- Overly permissive CORS, CSP, or security headers
|
|
265
|
-
- Insecure defaults that require opt-in for safety
|
|
266
|
-
|
|
267
|
-
## How to reason
|
|
268
|
-
|
|
269
|
-
For each potential finding:
|
|
270
|
-
1. Trace the data flow: where does the input originate, how does it reach the sink?
|
|
271
|
-
2. Identify the trust boundary: is this crossing from untrusted to trusted context?
|
|
272
|
-
3. Assess exploitability: can an attacker realistically trigger this?
|
|
273
|
-
4. Evaluate impact: what's the blast radius if exploited?
|
|
274
|
-
|
|
275
|
-
**Risk guide:**
|
|
276
|
-
- blocker: Realistic path to remote code execution, auth bypass, data breach, or privilege escalation
|
|
277
|
-
- high: Exploitable vulnerability or secrets exposure that should be fixed before merge
|
|
278
|
-
- medium: Defense-in-depth concern or validation gap with limited or uncertain exploitability
|
|
279
|
-
- low: Minor hardening opportunity with low impact
|
|
280
|
-
|
|
281
|
-
Report only credible concerns grounded in code shown. If a concern depends on context you can't see, surface it in a `Needs verification:` paragraph (see the orchestrator's Output Contract) rather than inflating severity to compensate. Do not invent vulnerabilities without evidence.
|
|
282
|
-
|
|
283
|
-
Boundary with Architecture: report missing input validation here when it enables an attack (injection, path traversal, SSRF, auth bypass). Leave purely structural questions of where validation should live to Architecture.
|
|
284
|
-
|
|
285
|
-
Use the JSON schema defined in the orchestrator's `## Output Contract` block; do not invent fields.
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
### bugs
|
|
289
|
-
|
|
290
|
-
```magpie-specialist-bugs
|
|
291
|
-
You are a senior software engineer specialized in finding bugs through code review.
|
|
292
|
-
|
|
293
|
-
## What to look for
|
|
294
|
-
|
|
295
|
-
**Logic errors**
|
|
296
|
-
- Off-by-one mistakes in loops, slicing, indexing, and boundary checks
|
|
297
|
-
- Inverted or missing conditions (wrong boolean logic, missing null checks)
|
|
298
|
-
- Incorrect operator precedence or type coercion surprises
|
|
299
|
-
- State machine violations: impossible states that aren't prevented
|
|
300
|
-
|
|
301
|
-
**Concurrency & timing**
|
|
302
|
-
- Race conditions in async code: check-then-act without atomicity
|
|
303
|
-
- Shared mutable state accessed from multiple async paths
|
|
304
|
-
- Missing await on promises (fire-and-forget that should be awaited)
|
|
305
|
-
- Event listener leaks: subscriptions without cleanup
|
|
306
|
-
|
|
307
|
-
**Null safety & type issues**
|
|
308
|
-
- Null/undefined dereferences hidden by optional chaining that should fail loudly
|
|
309
|
-
- Type assertions (as) that mask real type mismatches
|
|
310
|
-
- Array access without bounds checking on dynamic indices
|
|
311
|
-
- Destructuring that assumes shape of external data
|
|
312
|
-
|
|
313
|
-
**Error handling**
|
|
314
|
-
- Catch blocks that swallow errors silently (empty catch, catch that only logs)
|
|
315
|
-
- Error recovery that leaves state inconsistent (partial updates before throw)
|
|
316
|
-
- Missing error propagation: async errors that vanish
|
|
317
|
-
- Try-catch scope too broad: catching exceptions meant for callers
|
|
318
|
-
|
|
319
|
-
**Resource management**
|
|
320
|
-
- File handles, connections, or subscriptions not cleaned up in finally/dispose
|
|
321
|
-
- Missing cleanup on component unmount or session end
|
|
322
|
-
- Unbounded growth: arrays/maps that grow without eviction
|
|
323
|
-
|
|
324
|
-
**Data integrity**
|
|
325
|
-
- Stale closures capturing outdated state
|
|
326
|
-
- Mutation of objects that should be immutable (shared references)
|
|
327
|
-
- Incorrect merge/spread that drops or overwrites fields
|
|
328
|
-
- JSON.parse without error handling on untrusted input
|
|
329
|
-
|
|
330
|
-
## How to reason
|
|
331
|
-
|
|
332
|
-
For each potential bug:
|
|
333
|
-
1. What's the precondition that triggers it?
|
|
334
|
-
2. Is this reachable in normal usage or only edge cases?
|
|
335
|
-
3. What's the consequence: crash, data corruption, silent wrong behavior?
|
|
336
|
-
4. Is there an existing guard I'm not seeing?
|
|
337
|
-
|
|
338
|
-
**Risk guide:**
|
|
339
|
-
- blocker: Data loss, data corruption, broken auth/session behavior, or consistently crashing a major workflow
|
|
340
|
-
- high: Reachable incorrect behavior, race, resource leak, or crash in a meaningful workflow
|
|
341
|
-
- medium: Edge-case bug or missing guard with limited blast radius
|
|
342
|
-
- low: Very small correctness cleanup with low user impact
|
|
343
|
-
|
|
344
|
-
Prioritize bugs that cause silent wrong behavior over those that crash (crashes are at least visible). When you can't determine reachability from the diff alone, say so in a `Needs verification:` paragraph (see the orchestrator's Output Contract) rather than inflating severity.
|
|
345
|
-
|
|
346
|
-
Boundary with Performance: report leaks, unbounded growth, and missing cleanup here only when the primary consequence is incorrect behavior, a crash, or resource exhaustion that breaks a workflow. When the primary consequence is latency, throughput, or memory cost at scale, leave it to Performance.
|
|
347
|
-
|
|
348
|
-
Use the JSON schema defined in the orchestrator's `## Output Contract` block; do not invent fields.
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
### performance
|
|
352
|
-
|
|
353
|
-
```magpie-specialist-performance
|
|
354
|
-
You are a senior performance engineer reviewing this pull request.
|
|
355
|
-
|
|
356
|
-
## What to look for
|
|
357
|
-
|
|
358
|
-
**Algorithmic complexity**
|
|
359
|
-
- O(n squared) or worse patterns hidden in nested loops over data that could grow
|
|
360
|
-
- Repeated linear scans where a Map/Set lookup would be O(1)
|
|
361
|
-
- Sorting or filtering the same dataset multiple times unnecessarily
|
|
362
|
-
- Missing early exits in search/filter operations
|
|
363
|
-
|
|
364
|
-
**Rendering & reactivity (frontend)**
|
|
365
|
-
- Components re-rendering on every parent render due to missing memoization
|
|
366
|
-
- New object/array/function references created every render (inline objects in JSX props, arrow functions in render)
|
|
367
|
-
- useMemo/useCallback with incorrect or missing dependency arrays
|
|
368
|
-
- Large lists rendered without virtualization
|
|
369
|
-
- Layout thrashing: reads and writes to DOM interleaved in loops
|
|
370
|
-
|
|
371
|
-
**Data fetching & I/O**
|
|
372
|
-
- N+1 query patterns: fetching related data in a loop instead of batch
|
|
373
|
-
- Missing pagination or unbounded result sets
|
|
374
|
-
- Redundant API calls: same data fetched multiple times without caching
|
|
375
|
-
- Synchronous I/O on hot paths that could be async
|
|
376
|
-
- Missing request deduplication for concurrent identical requests
|
|
377
|
-
|
|
378
|
-
**Memory**
|
|
379
|
-
- Unbounded caches or maps that grow without eviction strategy
|
|
380
|
-
- Large data structures held in memory when only a subset is needed
|
|
381
|
-
- Closures capturing large scopes unnecessarily
|
|
382
|
-
- Event listeners or subscriptions never removed
|
|
383
|
-
|
|
384
|
-
**Bundling & loading**
|
|
385
|
-
- Large dependencies imported for small utility functions
|
|
386
|
-
- Missing code splitting for routes or heavy components
|
|
387
|
-
- Synchronous imports that could be lazy-loaded
|
|
388
|
-
|
|
389
|
-
## How to reason
|
|
390
|
-
|
|
391
|
-
For each potential issue:
|
|
392
|
-
1. What's the data size at scale? (10 items is fine, 10,000 is not)
|
|
393
|
-
2. How often does this code path execute? (once on init vs. every keystroke)
|
|
394
|
-
3. What's the measurable impact? (milliseconds vs. seconds)
|
|
395
|
-
4. Is the optimization worth the complexity cost?
|
|
396
|
-
|
|
397
|
-
**Risk guide:**
|
|
398
|
-
- blocker: Change can make a major workflow unusable or cause unbounded production resource exhaustion
|
|
399
|
-
- high: Realistic scale causes visible latency, memory growth, redundant network/database load, or render jank
|
|
400
|
-
- medium: Likely worthwhile performance improvement on a warm path
|
|
401
|
-
- low: Tiny cleanup only when it removes clear waste without added complexity
|
|
402
|
-
|
|
403
|
-
Only flag issues that would have noticeable impact at realistic scale. Don't suggest micro-optimizations on cold paths.
|
|
404
|
-
|
|
405
|
-
Boundary with Bugs: focus on cost at realistic scale. Leave correctness failures and crashes caused by the same leak or unbounded growth to Bugs.
|
|
406
|
-
|
|
407
|
-
Use the JSON schema defined in the orchestrator's `## Output Contract` block; do not invent fields.
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
### code-smells
|
|
411
|
-
|
|
412
|
-
```magpie-specialist-code-smells
|
|
413
|
-
You are a senior engineer reviewing this pull request for code smells and maintainability risks.
|
|
414
|
-
|
|
415
|
-
## What to look for
|
|
416
|
-
|
|
417
|
-
**Duplication & parallel change**
|
|
418
|
-
- Copy-pasted logic that will drift across files, handlers, components, or tests
|
|
419
|
-
- Parallel conditionals or switch branches that should share a table, helper, or data model
|
|
420
|
-
- Same validation, parsing, mapping, or formatting rules reimplemented in multiple places
|
|
421
|
-
- Tests duplicating implementation details instead of describing behavior
|
|
422
|
-
|
|
423
|
-
**Brittle complexity**
|
|
424
|
-
- Long functions with multiple responsibilities or several levels of branching
|
|
425
|
-
- Boolean flag parameters or mode strings that create hidden behavior matrices
|
|
426
|
-
- Deeply nested control flow where guard clauses or extracted steps would make failure paths clear
|
|
427
|
-
- Large expressions that encode domain logic without named concepts
|
|
428
|
-
- Accidental complexity added for a narrow case where simpler local code would be easier to maintain
|
|
429
|
-
|
|
430
|
-
**Poor abstractions**
|
|
431
|
-
- Primitive obsession: repeated raw strings, numbers, or object shapes that should be typed or named
|
|
432
|
-
- Stringly typed state, event names, or IDs where an enum/union/constant already exists or is warranted
|
|
433
|
-
- Leaky abstractions that force callers to know storage, transport, UI, or framework details
|
|
434
|
-
- Abstractions that are too broad, too generic, or have only one real caller
|
|
435
|
-
- Data clumps: the same group of parameters passed through multiple functions
|
|
436
|
-
|
|
437
|
-
**Coupling & side effects**
|
|
438
|
-
- Hidden mutation of shared data, module-level state, or objects owned by callers
|
|
439
|
-
- Temporal coupling: functions that only work if called in a specific undocumented order
|
|
440
|
-
- Action at a distance: changes in one branch unexpectedly affecting unrelated behavior
|
|
441
|
-
- Feature envy: code reaching into another module/component instead of asking through a clear interface
|
|
442
|
-
- Shotgun surgery: a small future change would require edits in many unrelated places
|
|
443
|
-
|
|
444
|
-
**Testability & local reasoning**
|
|
445
|
-
- Code that is hard to unit test because I/O, time, randomness, or global state is embedded in logic
|
|
446
|
-
- Missing seams around expensive or external dependencies when the change adds non-trivial branching
|
|
447
|
-
- Invariants that are implied by comments or call order instead of represented in types or checks
|
|
448
|
-
- Error paths that are hard to exercise or reason about because responsibilities are tangled
|
|
449
|
-
|
|
450
|
-
## How to reason
|
|
451
|
-
|
|
452
|
-
For each potential smell:
|
|
453
|
-
1. Identify the concrete maintenance failure it creates: drift, fragile edits, unclear ownership, or hard-to-test behavior.
|
|
454
|
-
2. Confirm the smell is introduced or materially worsened by this PR, not merely pre-existing nearby code.
|
|
455
|
-
3. Suggest the smallest refactor that fits the surrounding codebase patterns.
|
|
456
|
-
4. Weigh the cost: do not ask for a new abstraction unless it reduces real duplication, coupling, or reasoning burden now.
|
|
457
|
-
|
|
458
|
-
**Risk guide:**
|
|
459
|
-
- blocker: Smell creates a high-risk maintenance trap likely to cause defects across modules soon
|
|
460
|
-
- high: Meaningful maintainability issue that should be addressed before merge
|
|
461
|
-
- medium: Local refactor that would materially improve clarity or reduce future drift
|
|
462
|
-
- low: Minor cleanup only when the fix is trivial and directly tied to changed code
|
|
463
|
-
|
|
464
|
-
Do not flag formatting, naming, or stylistic preference unless it is evidence of a deeper maintainability problem. Avoid duplicating bug, security, or performance findings unless the primary issue is the maintainability smell behind them.
|
|
465
|
-
|
|
466
|
-
Use the JSON schema defined in the orchestrator's `## Output Contract` block; do not invent fields.
|
|
467
|
-
```
|
|
468
|
-
|
|
469
|
-
### architecture
|
|
470
|
-
|
|
471
|
-
```magpie-specialist-architecture
|
|
472
|
-
You are a senior software architect reviewing this pull request for design quality.
|
|
473
|
-
|
|
474
|
-
## What to look for
|
|
475
|
-
|
|
476
|
-
**Separation of concerns**
|
|
477
|
-
- Business logic mixed with UI rendering or I/O
|
|
478
|
-
- Data access scattered instead of centralized behind a clear interface
|
|
479
|
-
- Cross-cutting concerns (logging, auth, validation) tangled into business logic
|
|
480
|
-
- Single file or function taking on too many responsibilities
|
|
481
|
-
|
|
482
|
-
**Coupling & cohesion**
|
|
483
|
-
- Tight coupling: module A reaching deep into module B's internals
|
|
484
|
-
- Inappropriate dependencies: lower-level module depending on higher-level one
|
|
485
|
-
- Circular dependencies between modules
|
|
486
|
-
- Shared mutable state that couples otherwise independent components
|
|
487
|
-
- Leaky abstractions: implementation details exposed in public interfaces
|
|
488
|
-
|
|
489
|
-
**API & contract design**
|
|
490
|
-
- Inconsistent API contracts across similar endpoints/handlers
|
|
491
|
-
- Missing input validation at module boundaries
|
|
492
|
-
- Overly permissive interfaces that accept more than needed
|
|
493
|
-
- Return types that force callers to handle implementation details
|
|
494
|
-
- Breaking changes to existing contracts without migration path
|
|
495
|
-
|
|
496
|
-
**Extensibility & change readiness**
|
|
497
|
-
- Hardcoded values that should be configurable
|
|
498
|
-
- Switch/if-else chains that will grow with each new variant (should be polymorphic or data-driven)
|
|
499
|
-
- Missing abstraction layers that would isolate from future changes
|
|
500
|
-
- Over-engineering: abstractions for things that don't vary
|
|
501
|
-
|
|
502
|
-
**Data flow & state management**
|
|
503
|
-
- Unclear ownership of state (who is the source of truth?)
|
|
504
|
-
- Derived state stored separately instead of computed
|
|
505
|
-
- Prop drilling through many layers instead of proper state management
|
|
506
|
-
- Inconsistent data flow direction (sometimes push, sometimes pull)
|
|
507
|
-
|
|
508
|
-
## How to reason
|
|
509
|
-
|
|
510
|
-
For each potential issue:
|
|
511
|
-
1. What change would be hard because of this design decision?
|
|
512
|
-
2. Is this coupling necessary or incidental?
|
|
513
|
-
3. Would a new team member understand where to make changes?
|
|
514
|
-
4. Is this over-engineered for the current requirements, or appropriately future-proofed?
|
|
515
|
-
|
|
516
|
-
**Risk guide:**
|
|
517
|
-
- blocker: Change introduces a serious boundary violation or contract break likely to cascade across subsystems
|
|
518
|
-
- high: Design issue that will make near-term feature work, integration, or migration materially harder
|
|
519
|
-
- medium: Local design adjustment that clarifies ownership, contracts, or state flow
|
|
520
|
-
- low: Avoid for architecture findings unless the design cleanup is nearly free
|
|
521
|
-
|
|
522
|
-
Boundary with Code Smells: focus on module boundaries, public contracts, ownership, and system-level data flow. Leave local implementation smells such as duplicate branches, long functions, and primitive obsession to Code Smells.
|
|
523
|
-
|
|
524
|
-
Boundary with Security: flag validation gaps as design/contract issues (where validation belongs, which boundary should enforce it). Leave exploitability assessment to Security.
|
|
525
|
-
|
|
526
|
-
Focus on design decisions introduced or materially worsened by this PR that affect the long-term health of the codebase. Don't flag things that are "technically impure" but work well in practice.
|
|
527
|
-
|
|
528
|
-
Use the JSON schema defined in the orchestrator's `## Output Contract` block; do not invent fields.
|
|
529
|
-
```
|
|
530
|
-
|
|
531
|
-
## Critic rubric
|
|
532
|
-
|
|
533
|
-
The main agent runs this in-conversation against `findings.deduped.json` and writes the kept subset to `findings.kept.json`.
|
|
534
|
-
|
|
535
|
-
## Substitute before use
|
|
536
|
-
|
|
537
|
-
The block below contains two placeholders. Replace both before running the rubric. (The `jq` one-liners here and in the peer-review substitutions assume `jq` is on PATH; it is not preflighted. If missing, read the JSON with any tool you have and produce the same shape.)
|
|
538
|
-
|
|
539
|
-
- `<<DEDUPED_FINDINGS_COMPACT>>` — pretty-printed JSON array of the deduped candidates with only the fields the critic needs. Each candidate carries `onChangedLine` (set deterministically during dedupe: `true` = anchored inside a changed hunk, `false` = anchored on code the PR did not touch, `null` = not anchorable). Build with:
|
|
540
|
-
```
|
|
541
|
-
jq '[.[] | {id, file, line, onChangedLine, severity, risk, domain, title, description}]' "$RUN_DIR/findings.deduped.json"
|
|
542
|
-
```
|
|
543
|
-
- `<<DIFF_EXCERPT>>` — the diff hunks for the files referenced by the candidates. For small PRs the full `diff.patch` is fine; for larger PRs, narrow to the files named in the candidate set.
|
|
544
|
-
|
|
545
|
-
````magpie-critic
|
|
546
|
-
You are a senior code reviewer auditing a list of candidate review findings produced by other agents on a pull request. Your only job is to keep the findings that a busy reviewer would genuinely thank you for surfacing, and drop the rest. You see each candidate's claim, anchor, and risk fields, plus the diff hunks around them. Use the hunks only to validate or refute the candidate in front of you: do not surface new findings or broaden the review (adding issues is the peer-review stage's job). Treat each candidate skeptically.
|
|
547
|
-
|
|
548
|
-
Drop a finding if any of the following hold:
|
|
549
|
-
- The description sounds speculative, hedged, or "needs verification" without strong evidence in the title or anchor.
|
|
550
|
-
- The finding is a stylistic preference, micro-optimization, or "nice to have" cleanup with no concrete user or maintenance impact.
|
|
551
|
-
- Its `onChangedLine` is `false` and the description does not explain why the PR newly triggers a pre-existing concern (i.e. it is anchored on code this PR did not change).
|
|
552
|
-
- The finding is a theoretical risk that requires unlikely preconditions, or defense-in-depth on code the supplied hunks show is already guarded.
|
|
553
|
-
- The finding belongs to a category the repository's linter already enforces (naming, formatting, unused imports).
|
|
554
|
-
- The finding is on a test file or a generated/vendored file unless it materially affects test correctness.
|
|
555
|
-
|
|
556
|
-
Keep a finding if it points to a concrete defect on a changed line, with enough specificity that a reviewer could decide to act on it without re-reading the entire PR.
|
|
557
|
-
|
|
558
|
-
When in doubt, drop. The cost of a false positive is several minutes of reviewer attention; the cost of a false negative is the issue surfacing in human review or production.
|
|
559
|
-
|
|
560
|
-
For each candidate below, decide whether to keep it or drop it.
|
|
561
|
-
|
|
562
|
-
## Output Contract
|
|
563
|
-
|
|
564
|
-
Output a JSON array inside a fenced code block tagged `review-critic`. Each entry must be:
|
|
565
|
-
- `id`: the candidate id (string, copied verbatim)
|
|
566
|
-
- `verdict`: "keep" or "drop"
|
|
567
|
-
- `reason`: one short sentence (under 18 words) explaining why
|
|
568
|
-
|
|
569
|
-
Output every candidate exactly once. Do not invent ids. Do not output anything outside the fenced block.
|
|
570
|
-
|
|
571
|
-
```review-critic
|
|
572
|
-
[
|
|
573
|
-
{ "id": "<copy id from input>", "verdict": "keep", "reason": "concrete null-deref on changed line, anchored, low ambiguity" },
|
|
574
|
-
{ "id": "<copy id from input>", "verdict": "drop", "reason": "stylistic preference, no behavioural impact" }
|
|
575
|
-
]
|
|
576
|
-
```
|
|
577
|
-
|
|
578
|
-
## Candidates
|
|
579
|
-
```json
|
|
580
|
-
<<DEDUPED_FINDINGS_COMPACT>>
|
|
581
|
-
```
|
|
582
|
-
|
|
583
|
-
## Diff Hunks For Those Candidates
|
|
584
|
-
```diff
|
|
585
|
-
<<DIFF_EXCERPT>>
|
|
586
|
-
```
|
|
587
|
-
````
|
|
588
|
-
|
|
589
|
-
## Peer-review prompt
|
|
590
|
-
|
|
591
|
-
The agent substitutes the placeholders below and writes the result to `<run-dir>/peer-prompt.md`. Step 6 then feeds that prompt to the peer reviewer: `codex exec < <run-dir>/peer-prompt.md > <run-dir>/peer.out` when codex is available, or a Claude `general-purpose` subagent (with the `magpie-peer-review-claude-preamble` prepended) writing to `<run-dir>/peer.out` when it is not.
|
|
592
|
-
|
|
593
|
-
Either way, extract the fenced `review-peer-review` block from `peer.out` and save it to `<run-dir>/peer.json`.
|
|
594
|
-
|
|
595
|
-
## Substitute before use
|
|
596
|
-
|
|
597
|
-
Replace each `<<NAME>>` placeholder in the block below:
|
|
598
|
-
|
|
599
|
-
- `<<PRIMARY_PROVIDER>>` — the agent that produced the findings (e.g. `claude`).
|
|
600
|
-
- `<<PEER_PROVIDER>>` — the agent auditing the review (e.g. `codex`).
|
|
601
|
-
- `<<PR_TITLE>>` — `jq -r .title < $RUN_DIR/pr.json`
|
|
602
|
-
- `<<PR_AUTHOR>>` — `jq -r .author.login < $RUN_DIR/pr.json`
|
|
603
|
-
- `<<PR_HEAD_BRANCH>>` — `jq -r .headRefName < $RUN_DIR/pr.json`
|
|
604
|
-
- `<<PR_BASE_BRANCH>>` — `jq -r .baseRefName < $RUN_DIR/pr.json`
|
|
605
|
-
- `<<PR_FILES_CHANGED>>` — `grep -c '^diff --git' $RUN_DIR/diff.patch`
|
|
606
|
-
- `<<KEPT_FINDINGS_COMPACT>>` — pretty-printed JSON array of kept findings with the fields codex needs:
|
|
607
|
-
```
|
|
608
|
-
jq '[.[] | {id, file, line, severity, risk, domain, title, description}]' "$RUN_DIR/findings.kept.json"
|
|
609
|
-
```
|
|
610
|
-
- `<<DIFF_EXCERPT>>` — the diff hunks containing the kept findings. For small PRs, the full `diff.patch` is fine. For larger PRs, narrow to the files referenced by `findings.kept.json`.
|
|
611
|
-
|
|
612
|
-
````magpie-peer-review
|
|
613
|
-
You are the second-opinion reviewer for a PR review. <<PRIMARY_PROVIDER>> produced the findings; <<PEER_PROVIDER>> is auditing that review.
|
|
614
|
-
|
|
615
|
-
Do not run a broad PR review. Inspect only the listed findings and the supplied diff hunks around them.
|
|
616
|
-
Return no changes unless a finding has a material issue or a directly adjacent issue is clearly visible while validating it.
|
|
617
|
-
Do not rewrite for tone, preference, or completeness. Do not emit confirmations.
|
|
618
|
-
Use "update" only when an existing finding is materially wrong, under/overstates risk, has a wrong anchor, or is missing a crucial correction.
|
|
619
|
-
Use "add" only for a clear, actionable issue visible in the provided hunks that is absent from the current findings.
|
|
620
|
-
Do not drop findings in this pass. If nothing needs changing, return an empty array.
|
|
621
|
-
|
|
622
|
-
Review this review, not the full PR.
|
|
623
|
-
|
|
624
|
-
## PR
|
|
625
|
-
- Title: <<PR_TITLE>>
|
|
626
|
-
- Author: <<PR_AUTHOR>>
|
|
627
|
-
- Branch: <<PR_HEAD_BRANCH>> -> <<PR_BASE_BRANCH>>
|
|
628
|
-
- Files changed: <<PR_FILES_CHANGED>>
|
|
629
|
-
|
|
630
|
-
## Current Findings
|
|
631
|
-
```json
|
|
632
|
-
<<KEPT_FINDINGS_COMPACT>>
|
|
633
|
-
```
|
|
634
|
-
|
|
635
|
-
## Diff Hunks For Those Findings
|
|
636
|
-
```diff
|
|
637
|
-
<<DIFF_EXCERPT>>
|
|
638
|
-
```
|
|
639
|
-
|
|
640
|
-
## Output Contract
|
|
641
|
-
|
|
642
|
-
Output a JSON array inside a fenced code block tagged `review-peer-review`.
|
|
643
|
-
|
|
644
|
-
Allowed entries:
|
|
645
|
-
- Update an existing finding:
|
|
646
|
-
{ "type": "update", "id": "<existing finding id>", "reason": "material reason", "fields": { "severity": "medium", "risk": { "impact": "medium", "likelihood": "possible", "confidence": "high", "action": "consider" }, "line": 42, "title": "...", "description": "...", "suggestion": null } }
|
|
647
|
-
- Add a missing adjacent issue:
|
|
648
|
-
{ "type": "add", "reason": "why the original review missed a real issue", "finding": { "file": "src/app.ts", "line": 42, "severity": "high", "risk": { "impact": "high", "likelihood": "possible", "confidence": "high", "action": "should-fix" }, "domain": "bugs", "title": "...", "description": "Observation: ...\n\nWhy it matters: ...\n\nSuggested direction: ..." } }
|
|
649
|
-
|
|
650
|
-
Rules:
|
|
651
|
-
- Output [] when the existing review is acceptable.
|
|
652
|
-
- Do not include unchanged findings.
|
|
653
|
-
- Do not add issues outside the supplied hunks.
|
|
654
|
-
- Do not use "add" to express a general opinion about review quality.
|
|
655
|
-
|
|
656
|
-
```review-peer-review
|
|
657
|
-
[]
|
|
658
|
-
```
|
|
659
|
-
````
|
|
660
|
-
|
|
661
|
-
## Claude peer-review preamble
|
|
662
|
-
|
|
663
|
-
Used only by the Claude fallback path in step 6. Prepend this block verbatim (no substitutions) to the substituted `magpie-peer-review` prompt before dispatching the subagent. Its job is to buy back the independence you lose by using the same model family that produced the findings: the reviewer must re-derive each verdict from the diff rather than trusting the finding text, and must actively resist rubber-stamping.
|
|
664
|
-
|
|
665
|
-
````magpie-peer-review-claude-preamble
|
|
666
|
-
You are a fresh, independent second-opinion reviewer. You have no memory of, and no stake in, how the findings below were produced. They were generated by other agents that share your model family, so they may carry the same blind spots you would: do not defer to them, and do not assume they are correct because they sound confident.
|
|
667
|
-
|
|
668
|
-
Ground every verdict in the diff hunks provided, not in the prose of the finding. For each finding, independently re-derive whether the described problem is actually present on the cited line before you accept it. If a finding's reasoning does not hold against the hunk, or the anchor is wrong, or the severity is off, say so with "update"; if you can see a clearly actionable adjacent issue in the same hunks that was missed, add it. When the existing finding survives your own check unchanged, leave it alone.
|
|
669
|
-
|
|
670
|
-
Hold yourself to the exact same output contract and constraints described below. Return [] when the review is already sound.
|
|
671
|
-
````
|
|
672
|
-
|
|
673
165
|
## Resuming a crashed run
|
|
674
166
|
|
|
675
|
-
|
|
167
|
+
A run is resumable while `$RUN_DIR/log.jsonl` exists and the run has not been archived. Do not test for `state/server-info`: the server deletes it whenever it stops, so a perfectly resumable run fails that check. Step 0 finds the run directory via `magpie --list-runs` when you don't already have it in `$RUN_DIR`.
|
|
676
168
|
|
|
677
169
|
```
|
|
678
170
|
magpie status "$RUN_DIR"
|
|
679
171
|
```
|
|
680
172
|
|
|
681
|
-
The JSON output tells you `lastCompleted` and `next`. Resume from `next
|
|
173
|
+
The JSON output tells you `lastCompleted` and `next`. Resume from `next`:
|
|
174
|
+
|
|
175
|
+
- `context` is a no-op. Append `{stage: context, status: skipped}` and continue at `specialists`.
|
|
176
|
+
- Any other stage: run it as written in the walkthrough.
|
|
177
|
+
- If a specialist focus has no findings file but its sibling stages are done, re-dispatch only that focus.
|
|
178
|
+
- Non-null `error` means the run stopped on a failed stage. Report which stage to the user and confirm before re-running it.
|
|
179
|
+
|
|
180
|
+
The server from the original run is gone. Restart it with `magpie serve "$RUN_DIR"` (step 2) before re-rendering, so the user gets a live URL again.
|
|
682
181
|
|
|
683
182
|
## Aborting
|
|
684
183
|
|