@iceinvein/agent-skills 0.23.9 → 0.23.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/package.json +1 -1
  2. package/skills/index.json +2 -2
  3. package/skills/magpie/SKILL.md +21 -20
  4. package/skills/magpie/bin/magpie.ts +63 -2
  5. package/skills/magpie/evals/quality/README.md +74 -1
  6. package/skills/magpie/evals/quality/__tests__/probe-specialist.test.ts +498 -0
  7. package/skills/magpie/evals/quality/__tests__/replay-full.test.ts +9 -0
  8. package/skills/magpie/evals/quality/probe-specialist.ts +672 -0
  9. package/skills/magpie/evals/quality/replay-full.ts +6 -2
  10. package/skills/magpie/fixtures/fake-gh-with-lockfile.sh +37 -2
  11. package/skills/magpie/fixtures/fake-gh.sh +49 -2
  12. package/skills/magpie/references/critic.md +20 -4
  13. package/skills/magpie/references/proof.md +102 -0
  14. package/skills/magpie/references/scout.md +6 -1
  15. package/skills/magpie/references/specialists.md +15 -9
  16. package/skills/magpie/scripts/__tests__/cleanup-cmd.test.ts +103 -7
  17. package/skills/magpie/scripts/__tests__/cli.test.ts +69 -0
  18. package/skills/magpie/scripts/__tests__/critic-cmd.test.ts +46 -0
  19. package/skills/magpie/scripts/__tests__/critic.test.ts +11 -1
  20. package/skills/magpie/scripts/__tests__/dedupe-cmd.test.ts +20 -1
  21. package/skills/magpie/scripts/__tests__/git-diff.test.ts +23 -4
  22. package/skills/magpie/scripts/__tests__/handoff-cmd.test.ts +68 -0
  23. package/skills/magpie/scripts/__tests__/history.test.ts +232 -0
  24. package/skills/magpie/scripts/__tests__/impact-cmd.test.ts +477 -0
  25. package/skills/magpie/scripts/__tests__/impact-render.test.ts +365 -0
  26. package/skills/magpie/scripts/__tests__/impact.test.ts +915 -0
  27. package/skills/magpie/scripts/__tests__/incremental.test.ts +59 -8
  28. package/skills/magpie/scripts/__tests__/pipeline-e2e.test.ts +1 -1
  29. package/skills/magpie/scripts/__tests__/post-cmd.test.ts +58 -0
  30. package/skills/magpie/scripts/__tests__/pr-activity.test.ts +281 -0
  31. package/skills/magpie/scripts/__tests__/preview-cmd.test.ts +4 -4
  32. package/skills/magpie/scripts/__tests__/previous-findings.test.ts +267 -0
  33. package/skills/magpie/scripts/__tests__/proof-cmd.test.ts +260 -0
  34. package/skills/magpie/scripts/__tests__/proof.test.ts +226 -0
  35. package/skills/magpie/scripts/__tests__/refresh.test.ts +71 -0
  36. package/skills/magpie/scripts/__tests__/render-annotation.test.ts +34 -0
  37. package/skills/magpie/scripts/__tests__/render-findings.test.ts +75 -0
  38. package/skills/magpie/scripts/__tests__/render-progress.test.ts +9 -0
  39. package/skills/magpie/scripts/__tests__/setup-cmd.test.ts +376 -1
  40. package/skills/magpie/scripts/__tests__/shard-coverage.test.ts +79 -0
  41. package/skills/magpie/scripts/__tests__/skill-lint.test.ts +48 -2
  42. package/skills/magpie/scripts/__tests__/status-cmd.test.ts +20 -8
  43. package/skills/magpie/scripts/__tests__/types.test.ts +46 -0
  44. package/skills/magpie/scripts/cleanup-cmd.ts +88 -0
  45. package/skills/magpie/scripts/critic-cmd.ts +2 -0
  46. package/skills/magpie/scripts/critic.ts +4 -0
  47. package/skills/magpie/scripts/dedupe-cmd.ts +4 -0
  48. package/skills/magpie/scripts/evidence-filter.ts +10 -0
  49. package/skills/magpie/scripts/git-diff.ts +50 -19
  50. package/skills/magpie/scripts/handoff-cmd.ts +42 -3
  51. package/skills/magpie/scripts/history.ts +143 -0
  52. package/skills/magpie/scripts/impact-cmd.ts +202 -0
  53. package/skills/magpie/scripts/impact-render.ts +158 -0
  54. package/skills/magpie/scripts/impact.ts +622 -0
  55. package/skills/magpie/scripts/incremental.ts +44 -5
  56. package/skills/magpie/scripts/labels-cmd.ts +7 -3
  57. package/skills/magpie/scripts/post-cmd.ts +46 -0
  58. package/skills/magpie/scripts/pr-activity.ts +243 -0
  59. package/skills/magpie/scripts/preview-cmd.ts +3 -0
  60. package/skills/magpie/scripts/previous-findings.ts +181 -0
  61. package/skills/magpie/scripts/proof-cmd.ts +226 -0
  62. package/skills/magpie/scripts/proof.ts +150 -0
  63. package/skills/magpie/scripts/refresh.ts +11 -0
  64. package/skills/magpie/scripts/render-annotation.ts +17 -0
  65. package/skills/magpie/scripts/render-cmd.ts +12 -0
  66. package/skills/magpie/scripts/render-findings.ts +37 -1
  67. package/skills/magpie/scripts/render-progress.ts +3 -0
  68. package/skills/magpie/scripts/setup-cmd.ts +142 -11
  69. package/skills/magpie/scripts/shard-coverage.ts +53 -0
  70. package/skills/magpie/scripts/status-cmd.ts +2 -0
  71. package/skills/magpie/scripts/types.ts +39 -0
  72. package/skills/magpie/skill.json +1 -1
  73. package/skills/magpie/templates/styles.css +30 -0
  74. package/skills/sluice/scripts/status.sh +32 -13
  75. package/skills/sluice/skill.json +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iceinvein/agent-skills",
3
- "version": "0.23.9",
3
+ "version": "0.23.13",
4
4
  "description": "Install agent skills into AI coding tools",
5
5
  "author": "iceinvein",
6
6
  "license": "MIT",
package/skills/index.json CHANGED
@@ -227,7 +227,7 @@
227
227
  "name": "magpie",
228
228
  "description": "Interactive PR review pipeline. Runs five parallel specialist subagents (security, bugs, performance, code-smells, architecture) plus a once-per-PR checks pass that finds tests and controls able to pass without proving their purpose, drops findings whose quoted evidence is not in the code, dedupes, runs critic subagents that re-check each finding against the worktree and set its risk label, peer-reviews via codex exec (falling back to a Claude second opinion when codex is unavailable), and serves an interactive HTML report for selecting or dismissing findings to post via gh, recording the outcome per finding as labels. Bundles a Bun CLI put on PATH by the skill's postinstall step under a bunx install, or by the plugin's bin/ under a Claude Code plugin install. Use when the user asks to review a GitHub pull request. Local mode (setup --local) runs the same pipeline on the current branch's diff from its merge base, uncommitted and untracked work included, against the caller's live tree, with no server or posting, and hands the ranked findings back in the terminal for an implementing or orchestrating agent to address. Splits oversized diffs into budgeted shards and rebuilds the diff from the local clone when gh pr diff refuses it.",
229
229
  "type": "prompt",
230
- "version": "0.15.0"
230
+ "version": "0.16.1"
231
231
  },
232
232
  {
233
233
  "name": "migrate",
@@ -295,7 +295,7 @@
295
295
  "name": "sluice",
296
296
  "description": "Routes work by change shape into four channels (bypass, fast, main, deep) and applies only the rules each channel needs, so a one-line fix does not pay the cost of a multi-subsystem build. Carries nine rules as one-liners in the router and the full treatment in references read only on friction. Deep runs read the repo before designing, map the spec's intent to its decisions, and check spec against intent and plan against spec with a fresh reader, with plan.sh validate enforcing that every decision is covered. Checks the finished plan with plan.sh validate rather than trusting it to memory, seeds the run state from it, keeps a deep run's task breakdown in .sluice/run.json so a statusline segment, one status command and a SessionStart hook can answer where the run is (the hook prints a live run at every session start, compaction included), lists every live deep run and routed fast or main session on the machine in one board.sh view (drawn once, watched, or as JSON), and closes each run with a ledger read out of the session transcript: elapsed, tools, tokens, and what each dispatched agent cost where the transcript recorded it. Two Stop hooks hold a handback: one refuses a tree that moved since its last recorded check, the other refuses a changed existing test not proven to fail on the session's starting code (or recorded with a reason). Claude Code only; stands down where the superpowers pipeline governs the repo.",
297
297
  "type": "prompt",
298
- "version": "0.28.0"
298
+ "version": "0.28.2"
299
299
  },
300
300
  {
301
301
  "name": "temporal-coupling-detector",
@@ -16,7 +16,7 @@ Stop reading and follow these steps in order. Do not skip stages. Use the exact
16
16
 
17
17
  ### 0. Identify the PR
18
18
 
19
- A bare invocation (no arguments and no PR named), a request with no PR that asks to review the current branch, the working tree, or work in progress, or arguments starting `local` or `--` (any `--base` or `--intent-file` go to setup), is local mode: follow "Local mode" below in place of this step and stages 1 and 2, then run stages 3 to 7 as written, taking `TARGET` from Local mode.
19
+ A bare invocation (no arguments and no PR named), a request with no PR that asks to review the current branch, the working tree, or work in progress, or arguments starting `local` or `--` (any `--base` or `--intent-file` go to setup), is local mode: follow "Local mode" below in place of this step and stages 1 and 2, then run stages 3 to 7b as written, taking `TARGET` from Local mode.
20
20
 
21
21
  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 repo path into `$REPO` (default: the current working directory).
22
22
 
@@ -54,14 +54,12 @@ Setup then splits the filtered diff into shards, writing `$RUN_DIR/shards/manife
54
54
  and, when more than one shard results, `$RUN_DIR/shards/shard-<n>.patch`. `diff.patch`
55
55
  itself is never modified: shards are views over it. Re-split with a different budget
56
56
  using `magpie shard "$RUN_DIR" --budget <lines> --max-files <n>` (defaults: 6000 patch
57
- lines, 80 files). Re-splitting invalidates every existing
58
- `findings/<focus>.shard-<n>.json`, since a shard id then names a different file set:
59
- delete those files first, or stage 4's resume rule counts a pair as covered that
60
- nothing reviewed.
57
+ lines, 80 files). Delete every `findings/<focus>.shard-<n>.json` before re-splitting:
58
+ shard ids then name different files, and stage 4's resume rule would trust them.
61
59
 
62
- When a prior run exists for the same PR (active or archived under `~/.magpie/`), setup writes `$RUN_DIR/incremental.json` with `{previousRunId, previousSha, currentSha, sameSha}`. The post stage surfaces this as a "Incremental review since `<sha>`" trailer on the summary comment.
60
+ Setup writes `pr-activity.json` (checks, review threads, comments) and, on a re-review, `incremental.json` and `previous-findings.json` (last run's posted findings, whether their quoted code changed, and its dismissals).
63
61
 
64
- 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 in `$RUN_DIR/findings/tests.json`. That domain flows through dedupe/critic/peer-review like the LLM findings; no subagent is dispatched for it.
62
+ 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 in `$RUN_DIR/findings/tests.json`, reviewed downstream like the rest; no subagent is dispatched for it.
65
63
 
66
64
  ### 2. Serve
67
65
 
@@ -71,9 +69,9 @@ Start the HTML server in the background using the Bash tool with `run_in_backgro
71
69
  magpie serve "$RUN_DIR"
72
70
  ```
73
71
 
74
- Read `$RUN_DIR/state/server-info` for the URL; the server writes it asynchronously, so if it is missing, wait a moment and re-read (it appears within ~1s). Print to the user: "Open <url> in your browser to follow along."
72
+ Read `$RUN_DIR/state/server-info` for the URL (written within ~1s; re-read if missing). Print to the user: "Open <url> in your browser to follow along."
75
73
 
76
- The server shuts down after 30 idle minutes (an open report tab keeps it up) and deletes `state/server-info`. Nothing in the pipeline depends on it: re-run `magpie serve "$RUN_DIR"` to bring the report back.
74
+ The server stops after 30 idle minutes (an open report tab keeps it up); nothing depends on it, so re-run `magpie serve "$RUN_DIR"` to bring the report back.
77
75
 
78
76
  Render the first progress paint:
79
77
 
@@ -96,9 +94,11 @@ Append `{stage: context, status: done}` and re-render progress. If the scout wro
96
94
  Read `references/specialists.md` now, before dispatching anything: it holds the five focus blocks and the output contract every specialist prompt is built from. Assemble prompts from that file verbatim; written from memory they drift off the JSON contract, and `magpie dedupe` drops findings it cannot parse.
97
95
 
98
96
  Append `{stage: specialists, status: running}` to `$RUN_DIR/log.jsonl` and re-render
99
- progress, so the served page shows the stage as active rather than "Paused". Then read
97
+ progress. Then read
100
98
  `$RUN_DIR/shards/manifest.json`.
101
99
 
100
+ Run `magpie history "$RUN_DIR"` once; any output is part 6 of every specialist prompt.
101
+
102
102
  **One shard, zero shards, or no manifest** (a diff filtered down to nothing, e.g. a
103
103
  lockfile-only PR, yields `shards: []` in an otherwise normal manifest; a run predating
104
104
  this feature has no manifest at all): dispatch the five specialists in a single message,
@@ -118,14 +118,11 @@ many small files is split by the 80-file cap, so a larger `--budget` alone chang
118
118
  nothing); or review only the highest-risk shards, which means appending
119
119
  `{stage: shard-coverage, status: partial, reviewed: [<ids>], skipped: [<ids>]}` to
120
120
  `$RUN_DIR/log.jsonl` and telling the user in the terminal which shards go unreviewed.
121
- That log entry is the only record of the gap: the report has no unreviewed marker.
122
- Wait for the answer. This is the only interactive gate in the pipeline before the
123
- report, and it exists so that neither the cost nor a coverage gap is ever silent.
121
+ The report, summary comment and handoff name the skipped shards from that entry.
122
+ Wait for the answer; neither cost nor a coverage gap is ever silent.
124
123
 
125
124
  Dispatch by wave, one shard per wave, the five focuses in parallel within a wave,
126
- re-rendering progress between waves. That holds in-flight agents at five and makes a
127
- crash cheap to resume: only the `(focus, shard)` pairs whose findings file is missing
128
- need re-dispatching.
125
+ re-rendering progress between waves. That holds in-flight agents at five.
129
126
 
130
127
  After each subagent returns, append
131
128
  `{stage: specialist, focus: <focus>, shard: <n>, status: done, findings: <count>}` to
@@ -204,13 +201,17 @@ If codex returns non-zero on a batch, do not abort: record `{stage: peer-review,
204
201
 
205
202
  **Apply the verdicts (both paths).** Parse the merged verdicts and apply the `update` / `add` entries (an empty array means no change). A peer `fields.severity` (or `finding.severity` on an `add`) is ignored: severity is derived from `risk.impact`. Mint each `add`'s `id` as above before merging, since the peer contract does not carry ids. Then write `findings.final.json`. Re-render progress.
206
203
 
204
+ ### 7b. Proof
205
+
206
+ Append `{stage: proof, status: running}` and re-render progress. `magpie proof-prompt "$RUN_DIR"` fills `references/proof.md` for up to 8 must-fix or should-fix findings, printing `<prompt path>\t<output path>` each. On a PR run with any printed, first install `$WORKTREE`'s dependencies once with the repo's frozen-lockfile command (`npm ci`, `uv sync --frozen`, ...); on failure log `{stage: proof-deps, status: skipped, error}` and go on. Dispatch the prompts as stage 6 does its batches, then `magpie proof-apply "$RUN_DIR"`: it drops disproved findings to `proof-dropped.json`, marks the rest and logs `done`. On a non-zero exit, delete only the `proof-<id>.json` files or leftovers stderr names, then re-dispatch or re-apply.
207
+
207
208
  ### 8. Report
208
209
 
209
210
  ```
210
211
  magpie render "$RUN_DIR" findings
211
212
  ```
212
213
 
213
- The report shows the top 10 recommended (`must-fix`/`should-fix`, highest score first) and folds the rest. `--top <n>` is not saved (the stage 9 re-render and `magpie serve`'s auto-refresh show 10 again), so use it only when nothing will re-render.
214
+ The report shows the top 10 recommended (`must-fix`/`should-fix`, highest score first) and folds the rest. `--top <n>` is not saved, so use it only when nothing will re-render.
214
215
 
215
216
  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`).
216
217
 
@@ -294,9 +295,9 @@ The JSON output tells you `lastCompleted` and `next`. Resume from `next`:
294
295
  - Local run at `next: cleanup`: if the caller has not been sent the findings, re-run `magpie handoff` first (it only reads files).
295
296
  - If a specialist focus has no findings file but its sibling stages are done,
296
297
  re-dispatch only that focus. On a sharded run the unit is the `(focus, shard)` pair:
297
- read `shards/manifest.json`, and re-dispatch only the pairs with no
298
- `findings/<focus>.shard-<n>.json`. Never re-shard mid-run without deleting those
299
- files first (stage 1): the check would otherwise trust ids that moved.
298
+ re-dispatch only the pairs with no `findings/<focus>.shard-<n>.json`, skipping
299
+ shards a `shard-coverage: partial` entry skipped. Never re-shard mid-run without
300
+ deleting those files first (stage 1): shard ids move.
300
301
  - Non-null `error` means the run stopped on a failed stage. Report which stage to the user and confirm before re-running it.
301
302
 
302
303
  The original server is gone. Restart it with `magpie serve "$RUN_DIR"` (step 2) before re-rendering, so the user gets a live URL again.
@@ -13,6 +13,8 @@ Subcommands:
13
13
  (default origin/HEAD), committed and uncommitted
14
14
  target <run-dir> Print the directory findings are anchored against
15
15
  handoff <run-dir> Print local review findings as a ranked list
16
+ history <run-dir> Print what is already on the PR (open threads, comments,
17
+ dismissals, failing checks) for the specialist prompts
16
18
  serve <run-dir-or-id> Start the HTML server (accepts active or archived run id)
17
19
  dedupe <run-dir> Merge specialist findings into deduped set
18
20
  critic-prompt <run-dir> [--batch-size N]
@@ -20,13 +22,20 @@ Subcommands:
20
22
  critic-apply <run-dir> [--design-cap N]
21
23
  Apply critic verdicts, write findings.kept.json (no cap on
22
24
  code-smells + architecture keeps unless --design-cap is given)
25
+ proof-prompt <run-dir> Write one proof prompt per must-fix or should-fix finding, print
26
+ prompt and output paths
27
+ proof-apply <run-dir> Fold proof results into findings.final.json, drop the disproved
23
28
  shard <run-dir> [--budget N] [--max-files N]
24
- Re-split diff.patch into budgeted shards
29
+ Re-split diff.patch into budgeted shards (and the
30
+ impact map's per-shard files, when impact.json exists)
31
+ impact <run-dir> Write impact.json and impact*.md: what outside the diff
32
+ the change touches
25
33
  render <run-dir> <page> [--top N]
26
34
  Render progress.html or findings.html (findings recommends
27
35
  the top N, default 10, and folds the rest)
28
36
  labels <run-dir> Write labels.json (posted, dismissed, ignored per finding)
29
- cleanup <run-dir> Remove worktree, stop server, write labels, archive run
37
+ cleanup <run-dir> Remove worktree, stop server, write labels, archive run,
38
+ delete saved refs of closed PRs
30
39
  status <run-dir> Print highest completed stage
31
40
  open [id] Open findings.html in your browser (defaults to latest run)
32
41
  post <run-dir> --ids a,b Post the given finding ids via gh (rich body + optional summary)
@@ -244,6 +253,24 @@ const HANDLERS: Record<string, Handler> = {
244
253
  const { runCriticApply } = await import('../scripts/critic-cmd.ts')
245
254
  return runCriticApply(runDir, designCap !== undefined ? { designCap } : {})
246
255
  },
256
+ 'proof-prompt': async (args) => {
257
+ const runDir = args[0]
258
+ if (!runDir) {
259
+ process.stderr.write('proof-prompt: missing <run-dir>\n')
260
+ return 2
261
+ }
262
+ const { runProofPrompt } = await import('../scripts/proof-cmd.ts')
263
+ return runProofPrompt(runDir)
264
+ },
265
+ 'proof-apply': async (args) => {
266
+ const runDir = args[0]
267
+ if (!runDir) {
268
+ process.stderr.write('proof-apply: missing <run-dir>\n')
269
+ return 2
270
+ }
271
+ const { runProofApply } = await import('../scripts/proof-cmd.ts')
272
+ return runProofApply(runDir)
273
+ },
247
274
  shard: async (args) => {
248
275
  const runDir = args[0]
249
276
  if (!runDir) {
@@ -283,8 +310,25 @@ const HANDLERS: Record<string, Handler> = {
283
310
  process.stdout.write(
284
311
  `${manifest.shards.length} shard(s), ${manifest.totalFiles} files, ${manifest.totalLines} patch lines\n`,
285
312
  )
313
+ // The impact map's per-shard files name shard ids, which the re-split just renumbered.
314
+ // runImpact reports its own outcome; the split itself has already succeeded.
315
+ const { existsSync } = await import('node:fs')
316
+ const { join } = await import('node:path')
317
+ if (existsSync(join(runDir, 'impact.json'))) {
318
+ const { runImpact } = await import('../scripts/impact-cmd.ts')
319
+ await runImpact(runDir)
320
+ }
286
321
  return 0
287
322
  },
323
+ impact: async (args) => {
324
+ const runDir = args[0]
325
+ if (!runDir || runDir.startsWith('-')) {
326
+ process.stderr.write('impact: missing <run-dir>\n')
327
+ return 2
328
+ }
329
+ const { runImpact } = await import('../scripts/impact-cmd.ts')
330
+ return runImpact(runDir)
331
+ },
288
332
  render: async (args) => {
289
333
  const runDir = args[0]
290
334
  const page = args[1]
@@ -306,6 +350,22 @@ const HANDLERS: Record<string, Handler> = {
306
350
  const { runRender } = await import('../scripts/render-cmd.ts')
307
351
  return runRender(runDir, page, topN !== undefined ? { topN } : {})
308
352
  },
353
+ history: async (args) => {
354
+ const runDir = args[0]
355
+ if (!runDir || runDir.startsWith('-')) {
356
+ process.stderr.write('history: missing <run-dir>\n')
357
+ return 2
358
+ }
359
+ const { readHistory, renderHistory } = await import('../scripts/history.ts')
360
+ try {
361
+ const text = renderHistory(await readHistory(runDir))
362
+ if (text !== '') process.stdout.write(`${text}\n`)
363
+ } catch (err) {
364
+ process.stderr.write(`history: ${err instanceof Error ? err.message : String(err)}\n`)
365
+ return 1
366
+ }
367
+ return 0
368
+ },
309
369
  labels: async (args) => {
310
370
  const runDir = args[0]
311
371
  if (!runDir) {
@@ -335,6 +395,7 @@ const HANDLERS: Record<string, Handler> = {
335
395
  runDir,
336
396
  repoPath,
337
397
  gitBin: process.env.MAGPIE_GIT_BIN || 'git',
398
+ ghBin: process.env.MAGPIE_GH_BIN || 'gh',
338
399
  killGraceMs,
339
400
  })
340
401
  },
@@ -138,7 +138,8 @@ Re-runs stages 3 to 6 (context, specialists, dedupe, critic) on the run's `diff.
138
138
  `results/<ts>-full-<runId>.json` with `recall`, `recallVerdicts`, `judgeModel` and
139
139
  `judgeCostUsd` all null, plus `log`, `shardManifest`, `findingsFiles`, `dedupedCount`,
140
140
  `criticDropped`, `evidenceDropped` and `thresholdDropped` read from the scratch run dir
141
- before it is deleted. `shardCoverage` is derived from the manifest and the findings file
141
+ before it is deleted, and `impactBytes`, the size of `impact.md`. It is null unless
142
+ `magpie impact` was run on the replay's run dir, which no review stage does now. `shardCoverage` is derived from the manifest and the findings file
142
143
  names: a shard counts as reviewed when any specialist wrote a file for it, so it overstates
143
144
  a shard only some focuses reviewed. The printed line ends with `, shards <reviewed>/<total>`.
144
145
  4. When the run has a recall set (see [Recall](#recall)), judges the new kept findings
@@ -153,6 +154,78 @@ spend cap; `claude -p` has no `--max-cost-usd` flag. Hitting the cap stops the s
153
154
  and the replay then fails without scoring, on Claude's error result or on the missing
154
155
  `findings.kept.json`.
155
156
 
157
+ ## Specialist probe
158
+
159
+ ```
160
+ bun evals/quality/probe-specialist.ts --corpus <runId> --repo <path-to-local-clone> \
161
+ --focus <focus> --file <diff path> --misses <id,id> --arm base|impact --repeats <n> \
162
+ [--max-cost-usd N] [--judge-model M] [--dry-run]
163
+ ```
164
+
165
+ Runs one specialist on one shard, with (`impact`) or without (`base`) the impact map in
166
+ its prompt, and judges its findings against the named misses from the run's recall set.
167
+ It asks a narrower question than a full replay, for about a tenth of the cost.
168
+
169
+ The `impact` arm needs a `references/specialists.md` that carries a `magpie-impact-part`
170
+ block, as it did at commit 731a686 (since reverted). Without that block the probe exits
171
+ before any paid session, naming the missing block.
172
+
173
+ Repeats run one after another, each in its own scratch run dir and worktree:
174
+
175
+ 1. Scaffolds the run dir as the full replay does (worktree at the PR head, `pr.json`,
176
+ `diff.patch` and `brief.json` copied, a `setup` done line, then `magpie shard`), and
177
+ picks the shard whose files include `--file`; no such shard exits 1, naming the file.
178
+ 2. Impact arm only: `magpie impact`. A skipped impact stage fails the probe, since the arm
179
+ would then be a base arm. The prompt then carries `Outside the diff: <path>` under
180
+ `Diff:` and the `magpie-impact-part` block, with `<top entries>` filled from the
181
+ shard's `impact.shard-<n>.brief.md` and `<the path above>` with the path
182
+ (`impact.md` and `impact.brief.md` on an unsharded run). A shard with no impact file
183
+ exits 1, naming the shard, before any session is paid for.
184
+ 3. Builds the prompt from this checkout's `references/specialists.md` the way stage 4
185
+ does: focus block, run header, Output Contract, the excluded-files block when the
186
+ corpus run has `excluded-files.json`, and the brief rendered from `brief.json`.
187
+ 4. Runs `claude -p --output-format stream-json --verbose --allowedTools
188
+ Bash,Read,Grep,Glob,Write --max-budget-usd <N>` from the worktree, prompt on stdin.
189
+ 5. Writes `results/<ts>-probe-<runId>-<focus>-s<shard>-<arm>-r<k>.json` as soon as the
190
+ session ends, with `costUsd` and `sessionError` (a non-zero exit, an `is_error` result
191
+ such as a spent budget, or no result event; the probe then exits 1 after finishing).
192
+ `transcriptBadLines` counts transcript lines that are not JSON (a killed session cuts
193
+ its last line off); they are skipped, not fatal. The results dir is checked writable
194
+ before the session starts. Each later step fills its fields and rewrites the file; a
195
+ step that throws records `error`, rewrites it, prints one stderr line naming the
196
+ repeat and moves on to the next repeat, and the command exits 1 at the end. A failure
197
+ before the session (setup, worktree, a missing impact file) stops every repeat. In
198
+ order:
199
+ - `findings`, from the focus's findings file for the shard, numbering any finding
200
+ with no id as `<focus>-s<n>-<i>`. A missing file records `findings: 0` and
201
+ `missingFindings` with the reason rather than failing. `readImpact`: the session
202
+ opened the impact file with the Read tool (a Bash `cat` is not counted); null on
203
+ the base arm.
204
+ - `citesOutside`: findings whose description cites a `file:line` the shard's impact
205
+ Markdown lists outside the shard. The base arm runs `magpie impact` after its
206
+ session ends, so both arms count against the same map. It is a lower bound: only an
207
+ exact `path:line` match counts, so a citation by line range or by a nearby line is
208
+ missed.
209
+ - `judged`, `caught`, `verdicts` and `judgeCostUsd` from `judgeRecall`. With no
210
+ findings the judge is not called, `judged` stays false and `notJudged` says why.
211
+ 6. Removes the worktree and scratch dir whatever happened. A probe killed before its
212
+ cleanup ran leaves a stale worktree registered in the clone: run
213
+ `git -C <repo> worktree prune` there.
214
+
215
+ `--dry-run` stops after step 3, prints the chosen shard and the assembled prompt, cleans
216
+ up and exits 0. It calls no model and spends nothing.
217
+
218
+ **Reading results:** a phase A tally counts only runs with `judged: true` or with zero
219
+ findings (`findings: 0`); a run with an `error`, or with findings that were never judged,
220
+ is left out and re-run. Findings are judged straight from the specialist, before dedupe's
221
+ evidence filter, on both arms alike, so a finding dedupe would drop can still count as a
222
+ catch.
223
+
224
+ **Cost:** one specialist session per repeat, about $1.1 to $1.3 on the corpus PRs, capped
225
+ by `--max-cost-usd` (default 3, passed as `--max-budget-usd`), plus one judge call when
226
+ there are findings. A session that hits the cap is recorded with its cost and
227
+ `sessionError`, and its findings are still read and judged.
228
+
156
229
  ## Recall
157
230
 
158
231
  The labels above only score findings magpie raised. The recall set scores the other side: