@iceinvein/agent-skills 0.21.5 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/README.md +10 -1
  2. package/package.json +4 -1
  3. package/skills/bug-hunter/SKILL.md +87 -0
  4. package/skills/bug-hunter/evals/README.md +287 -0
  5. package/skills/bug-hunter/evals/baselines/claude-opus-5-5.json +93 -0
  6. package/skills/bug-hunter/evals/bug-cites-intent-from-spec/case.yaml +4 -0
  7. package/skills/bug-hunter/evals/bug-cites-intent-from-spec/fixture.sh +71 -0
  8. package/skills/bug-hunter/evals/bug-cites-intent-from-spec/graders/bug-cites-the-spec.md +36 -0
  9. package/skills/bug-hunter/evals/bug-cites-intent-from-spec/graders/bug-hunter-fired.md +5 -0
  10. package/skills/bug-hunter/evals/bug-cites-intent-from-spec/graders/intent-written.md +8 -0
  11. package/skills/bug-hunter/evals/bug-cites-intent-from-spec/prompt.md +11 -0
  12. package/skills/bug-hunter/evals/callers-tree-unchanged/case.yaml +4 -0
  13. package/skills/bug-hunter/evals/callers-tree-unchanged/fixture.sh +67 -0
  14. package/skills/bug-hunter/evals/callers-tree-unchanged/graders/bug-hunter-fired.md +5 -0
  15. package/skills/bug-hunter/evals/callers-tree-unchanged/graders/output-ignores-itself.md +11 -0
  16. package/skills/bug-hunter/evals/callers-tree-unchanged/graders/source-unchanged.md +10 -0
  17. package/skills/bug-hunter/evals/callers-tree-unchanged/graders/tests-unchanged.md +10 -0
  18. package/skills/bug-hunter/evals/callers-tree-unchanged/graders/tree-unchanged.md +15 -0
  19. package/skills/bug-hunter/evals/callers-tree-unchanged/prompt.md +11 -0
  20. package/skills/bug-hunter/evals/correct-code-has-no-bugs/case.yaml +4 -0
  21. package/skills/bug-hunter/evals/correct-code-has-no-bugs/fixture.sh +82 -0
  22. package/skills/bug-hunter/evals/correct-code-has-no-bugs/graders/bug-hunter-fired.md +5 -0
  23. package/skills/bug-hunter/evals/correct-code-has-no-bugs/graders/bugs-empty.md +18 -0
  24. package/skills/bug-hunter/evals/correct-code-has-no-bugs/graders/written-with-write-tool.md +13 -0
  25. package/skills/bug-hunter/evals/correct-code-has-no-bugs/prompt.md +11 -0
  26. package/skills/bug-hunter/evals/impossible-value-is-a-bug/case.yaml +4 -0
  27. package/skills/bug-hunter/evals/impossible-value-is-a-bug/fixture.sh +68 -0
  28. package/skills/bug-hunter/evals/impossible-value-is-a-bug/graders/bug-for-sixty-seconds.md +37 -0
  29. package/skills/bug-hunter/evals/impossible-value-is-a-bug/graders/bug-hunter-fired.md +5 -0
  30. package/skills/bug-hunter/evals/impossible-value-is-a-bug/prompt.md +11 -0
  31. package/skills/bug-hunter/evals/proves-a-spec-boundary-bug/case.yaml +4 -0
  32. package/skills/bug-hunter/evals/proves-a-spec-boundary-bug/fixture.sh +79 -0
  33. package/skills/bug-hunter/evals/proves-a-spec-boundary-bug/graders/bug-cites-the-limit.md +31 -0
  34. package/skills/bug-hunter/evals/proves-a-spec-boundary-bug/graders/bug-hunter-fired.md +5 -0
  35. package/skills/bug-hunter/evals/proves-a-spec-boundary-bug/graders/findings-written.md +10 -0
  36. package/skills/bug-hunter/evals/proves-a-spec-boundary-bug/prompt.md +11 -0
  37. package/skills/bug-hunter/evals/rules.json +185 -0
  38. package/skills/bug-hunter/evals/silent-spec-is-an-ambiguity/case.yaml +4 -0
  39. package/skills/bug-hunter/evals/silent-spec-is-an-ambiguity/fixture.sh +97 -0
  40. package/skills/bug-hunter/evals/silent-spec-is-an-ambiguity/graders/bug-hunter-fired.md +5 -0
  41. package/skills/bug-hunter/evals/silent-spec-is-an-ambiguity/graders/bugs-empty.md +18 -0
  42. package/skills/bug-hunter/evals/silent-spec-is-an-ambiguity/graders/cap-is-an-ambiguity.md +12 -0
  43. package/skills/bug-hunter/evals/silent-spec-is-an-ambiguity/graders/written-with-write-tool.md +13 -0
  44. package/skills/bug-hunter/evals/silent-spec-is-an-ambiguity/prompt.md +11 -0
  45. package/skills/bug-hunter/evals/spec-outranks-target-docstring/case.yaml +4 -0
  46. package/skills/bug-hunter/evals/spec-outranks-target-docstring/fixture.sh +82 -0
  47. package/skills/bug-hunter/evals/spec-outranks-target-docstring/graders/bug-cites-the-spec.md +40 -0
  48. package/skills/bug-hunter/evals/spec-outranks-target-docstring/graders/bug-hunter-fired.md +5 -0
  49. package/skills/bug-hunter/evals/spec-outranks-target-docstring/prompt.md +11 -0
  50. package/skills/bug-hunter/references/findings-format.md +82 -0
  51. package/skills/bug-hunter/references/scenario-catalog.md +92 -0
  52. package/skills/bug-hunter/skill.json +24 -0
  53. package/skills/index.json +18 -6
  54. package/skills/magpie/README.md +5 -3
  55. package/skills/magpie/SKILL.md +40 -15
  56. package/skills/magpie/bin/magpie.ts +83 -7
  57. package/skills/magpie/evals/README.md +20 -4
  58. package/skills/magpie/evals/baselines/claude-opus-5-5.json +69 -0
  59. package/skills/magpie/evals/local-mode-hands-back/case.yaml +4 -0
  60. package/skills/magpie/evals/local-mode-hands-back/fixture.sh +300 -0
  61. package/skills/magpie/evals/local-mode-hands-back/graders/branch-was-reachable.md +5 -0
  62. package/skills/magpie/evals/local-mode-hands-back/graders/cleanup-after-handoff.md +6 -0
  63. package/skills/magpie/evals/local-mode-hands-back/graders/handoff-was-run.md +6 -0
  64. package/skills/magpie/evals/local-mode-hands-back/graders/nothing-served-or-posted.md +7 -0
  65. package/skills/magpie/evals/local-mode-hands-back/graders/reply-lists-both-findings.md +10 -0
  66. package/skills/magpie/evals/local-mode-hands-back/graders/skill-fired.md +5 -0
  67. package/skills/magpie/evals/local-mode-hands-back/prompt.md +11 -0
  68. package/skills/magpie/evals/quality/README.md +73 -2
  69. package/skills/magpie/evals/quality/__tests__/recall.test.ts +234 -0
  70. package/skills/magpie/evals/quality/__tests__/replay-full.test.ts +164 -0
  71. package/skills/magpie/evals/quality/corpus.ts +4 -1
  72. package/skills/magpie/evals/quality/recall.ts +249 -0
  73. package/skills/magpie/evals/quality/replay-critic.ts +3 -0
  74. package/skills/magpie/evals/quality/replay-full.ts +168 -6
  75. package/skills/magpie/evals/rules.json +200 -0
  76. package/skills/magpie/references/checks.md +78 -0
  77. package/skills/magpie/references/peer-review.md +7 -0
  78. package/skills/magpie/references/scout.md +12 -5
  79. package/skills/magpie/references/specialists.md +10 -8
  80. package/skills/magpie/scripts/__tests__/cleanup-cmd.test.ts +94 -0
  81. package/skills/magpie/scripts/__tests__/critic-cmd.test.ts +18 -0
  82. package/skills/magpie/scripts/__tests__/dedupe-cmd.test.ts +80 -1
  83. package/skills/magpie/scripts/__tests__/handoff-cmd.test.ts +319 -0
  84. package/skills/magpie/scripts/__tests__/housekeeping-cmd.test.ts +14 -0
  85. package/skills/magpie/scripts/__tests__/local-diff.test.ts +275 -0
  86. package/skills/magpie/scripts/__tests__/pipeline-e2e.test.ts +1 -0
  87. package/skills/magpie/scripts/__tests__/resolve-run.test.ts +28 -0
  88. package/skills/magpie/scripts/__tests__/server.test.ts +30 -1
  89. package/skills/magpie/scripts/__tests__/setup-cmd.test.ts +324 -1
  90. package/skills/magpie/scripts/__tests__/skill-lint.test.ts +8 -5
  91. package/skills/magpie/scripts/__tests__/status-cmd.test.ts +44 -0
  92. package/skills/magpie/scripts/__tests__/target.test.ts +84 -0
  93. package/skills/magpie/scripts/__tests__/types.test.ts +2 -1
  94. package/skills/magpie/scripts/cleanup-cmd.ts +5 -1
  95. package/skills/magpie/scripts/critic-cmd.ts +2 -1
  96. package/skills/magpie/scripts/dedupe-cmd.ts +15 -5
  97. package/skills/magpie/scripts/handoff-cmd.ts +132 -0
  98. package/skills/magpie/scripts/housekeeping-cmd.ts +7 -5
  99. package/skills/magpie/scripts/local-diff.ts +228 -0
  100. package/skills/magpie/scripts/post-cmd.ts +1 -0
  101. package/skills/magpie/scripts/render-annotation.ts +1 -0
  102. package/skills/magpie/scripts/resolve-run.ts +17 -3
  103. package/skills/magpie/scripts/server.ts +9 -1
  104. package/skills/magpie/scripts/setup-cmd.ts +241 -49
  105. package/skills/magpie/scripts/status-cmd.ts +22 -6
  106. package/skills/magpie/scripts/target.ts +56 -0
  107. package/skills/magpie/scripts/types.ts +1 -0
  108. package/skills/magpie/skill.json +2 -2
  109. package/skills/migrate/evals/README.md +13 -0
  110. package/skills/migrate/evals/baselines/claude-opus-5-5.json +129 -0
  111. package/skills/migrate/evals/rules.json +160 -0
  112. package/skills/migrate/skill.json +10 -4
  113. package/skills/scope-estimate/README.md +173 -0
  114. package/skills/scope-estimate/SKILL.md +168 -0
  115. package/skills/scope-estimate/references/capability-map.md +122 -0
  116. package/skills/scope-estimate/references/deliverables.md +60 -0
  117. package/skills/scope-estimate/references/requirements.md +104 -0
  118. package/skills/scope-estimate/references/schedule.md +138 -0
  119. package/skills/scope-estimate/scripts/__tests__/schedule.test.ts +366 -0
  120. package/skills/scope-estimate/scripts/schedule.ts +553 -0
  121. package/skills/scope-estimate/skill.json +19 -0
  122. package/skills/scope-estimate/templates/plan.example.json +33 -0
  123. package/skills/sluice/SKILL.md +20 -4
  124. package/skills/sluice/evals/README.md +119 -6
  125. package/skills/sluice/evals/announcement-reaches-the-ledger/fixture.sh +32 -19
  126. package/skills/sluice/evals/announcement-reaches-the-ledger/graders/routes-main-before-source.md +14 -0
  127. package/skills/sluice/evals/announcement-reaches-the-ledger/prompt.md +2 -2
  128. package/skills/sluice/evals/baselines/claude-opus-5-5.json +237 -0
  129. package/skills/sluice/evals/deep-run-blocks-on-a-real-decision/fixture.sh +19 -12
  130. package/skills/sluice/evals/deep-run-fans-out/graders/task-1-merged-back.md +8 -0
  131. package/skills/sluice/evals/deep-run-fans-out/graders/task-2-merged-back.md +8 -0
  132. package/skills/sluice/evals/deep-run-fans-out/graders/task-3-merged-back.md +6 -0
  133. package/skills/sluice/evals/deep-run-fans-out/graders/worktree-per-implementer.md +12 -0
  134. package/skills/sluice/evals/deep-run-hunts-after-the-flip/case.yaml +5 -0
  135. package/skills/sluice/evals/deep-run-hunts-after-the-flip/fixture.sh +258 -0
  136. package/skills/sluice/evals/deep-run-hunts-after-the-flip/graders/bug-hunter-fired.md +5 -0
  137. package/skills/sluice/evals/deep-run-hunts-after-the-flip/graders/four-attempts-allowed.md +34 -0
  138. package/skills/sluice/evals/deep-run-hunts-after-the-flip/graders/fourth-attempt-tested.md +20 -0
  139. package/skills/sluice/evals/deep-run-hunts-after-the-flip/graders/hunt-before-the-final-review.md +21 -0
  140. package/skills/sluice/evals/deep-run-hunts-after-the-flip/graders/record-has-a-hunt-section.md +11 -0
  141. package/skills/sluice/evals/deep-run-hunts-after-the-flip/graders/sluice-fired.md +5 -0
  142. package/skills/sluice/evals/deep-run-hunts-after-the-flip/prompt.md +12 -0
  143. package/skills/sluice/evals/deep-run-survives-a-milestone/fixture.sh +46 -24
  144. package/skills/sluice/evals/fast-leaves-an-unrelated-red-test-alone/case.yaml +4 -0
  145. package/skills/sluice/evals/fast-leaves-an-unrelated-red-test-alone/fixture.sh +108 -0
  146. package/skills/sluice/evals/fast-leaves-an-unrelated-red-test-alone/graders/deploy-names-its-steps.md +9 -0
  147. package/skills/sluice/evals/fast-leaves-an-unrelated-red-test-alone/graders/kept-status-by-changing-code.md +12 -0
  148. package/skills/sluice/evals/fast-leaves-an-unrelated-red-test-alone/graders/sluice-fired.md +5 -0
  149. package/skills/sluice/evals/fast-leaves-an-unrelated-red-test-alone/graders/status-test-unchanged.md +6 -0
  150. package/skills/sluice/evals/fast-leaves-an-unrelated-red-test-alone/prompt.md +11 -0
  151. package/skills/sluice/evals/fast-updates-the-test-the-change-replaces/case.yaml +4 -0
  152. package/skills/sluice/evals/fast-updates-the-test-the-change-replaces/fixture.sh +73 -0
  153. package/skills/sluice/evals/fast-updates-the-test-the-change-replaces/graders/proved-after-the-last-edit.md +18 -0
  154. package/skills/sluice/evals/fast-updates-the-test-the-change-replaces/graders/sluice-fired.md +5 -0
  155. package/skills/sluice/evals/fast-updates-the-test-the-change-replaces/graders/test-expects-the-new-line.md +5 -0
  156. package/skills/sluice/evals/fast-updates-the-test-the-change-replaces/graders/updated-without-asking.md +11 -0
  157. package/skills/sluice/evals/fast-updates-the-test-the-change-replaces/prompt.md +11 -0
  158. package/skills/sluice/evals/fast-verifies-before-handback/case.yaml +4 -0
  159. package/skills/sluice/evals/fast-verifies-before-handback/fixture.sh +73 -0
  160. package/skills/sluice/evals/fast-verifies-before-handback/graders/quiet-flag-implemented.md +5 -0
  161. package/skills/sluice/evals/fast-verifies-before-handback/graders/sluice-fired.md +5 -0
  162. package/skills/sluice/evals/fast-verifies-before-handback/graders/verified-after-the-last-edit.md +18 -0
  163. package/skills/sluice/evals/fast-verifies-before-handback/prompt.md +11 -0
  164. package/skills/sluice/evals/main-hunts-a-checkable-claim/case.yaml +5 -0
  165. package/skills/sluice/evals/main-hunts-a-checkable-claim/fixture.sh +64 -0
  166. package/skills/sluice/evals/main-hunts-a-checkable-claim/graders/announces-main-channel.md +12 -0
  167. package/skills/sluice/evals/main-hunts-a-checkable-claim/graders/bug-hunter-fired.md +5 -0
  168. package/skills/sluice/evals/main-hunts-a-checkable-claim/graders/hunt-after-the-source-edits.md +12 -0
  169. package/skills/sluice/evals/main-hunts-a-checkable-claim/graders/last-page-holds-the-remainder.md +27 -0
  170. package/skills/sluice/evals/main-hunts-a-checkable-claim/graders/remainder-page-tested.md +21 -0
  171. package/skills/sluice/evals/main-hunts-a-checkable-claim/graders/sluice-fired.md +5 -0
  172. package/skills/sluice/evals/main-hunts-a-checkable-claim/prompt.md +12 -0
  173. package/skills/sluice/evals/main-new-interface/graders/shape-agreed-before-building.md +8 -4
  174. package/skills/sluice/evals/main-skips-the-hunt-without-a-claim/case.yaml +5 -0
  175. package/skills/sluice/evals/main-skips-the-hunt-without-a-claim/fixture.sh +73 -0
  176. package/skills/sluice/evals/main-skips-the-hunt-without-a-claim/graders/announces-main-channel.md +12 -0
  177. package/skills/sluice/evals/main-skips-the-hunt-without-a-claim/graders/no-hunt.md +12 -0
  178. package/skills/sluice/evals/main-skips-the-hunt-without-a-claim/graders/skip-said-in-one-line.md +21 -0
  179. package/skills/sluice/evals/main-skips-the-hunt-without-a-claim/graders/sluice-fired.md +5 -0
  180. package/skills/sluice/evals/main-skips-the-hunt-without-a-claim/prompt.md +12 -0
  181. package/skills/sluice/evals/rules.json +375 -0
  182. package/skills/sluice/references/deep-channel.md +48 -6
  183. package/skills/sluice/references/finish.md +5 -0
  184. package/skills/sluice/references/review.md +34 -0
  185. package/skills/sluice/references/status.md +17 -4
  186. package/skills/sluice/references/test-first.md +24 -4
  187. package/skills/sluice/references/verify.md +38 -0
  188. package/skills/sluice/scripts/content-digest.sh +65 -0
  189. package/skills/sluice/scripts/run-stats.sh +23 -8
  190. package/skills/sluice/scripts/session-start.sh +44 -2
  191. package/skills/sluice/scripts/status.sh +371 -13
  192. package/skills/sluice/scripts/stop-guard.sh +171 -24
  193. package/skills/sluice/scripts/test-changes.sh +135 -0
  194. package/skills/sluice/skill.json +2 -2
  195. package/skills/terse/evals/README.md +16 -0
  196. package/skills/terse/evals/baselines/claude-opus-5-5.json +105 -0
  197. package/skills/terse/evals/rules.json +161 -0
  198. package/skills/terse/skill.json +1 -1
  199. package/skills/sluice/evals/announcement-reaches-the-ledger/graders/escalates-fast-to-main.md +0 -12
package/README.md CHANGED
@@ -29,6 +29,7 @@ Auto-detects Claude Code, Cursor, Codex, or Gemini CLI. Use `--tool claude` to t
29
29
  | Skill | What it does |
30
30
  |-------|--------------|
31
31
  | **migrate** | Walks a legacy codebase through probe, enumerate, seam, extract, parity, queue, adjudicate and handoff: measured surface coverage, an empirically derived capability seam, cited requirements, a parity plan, a batch decision queue, and work items emitted to markdown, GitHub or a flow target with coverage and forecast read back. Bundles a Bun CLI that enforces the coverage arithmetic and phase ordering instead of trusting it. |
32
+ | **scope-estimate** | The lighter path for a proposal: read-only discovery, a capability register with status and disposition, sized functional requirements, contracts-first work packages, and a build schedule across engineers x worktrees at fast, planning and floor rates. Bundles a Bun scheduler that refuses a plan missing or double-counting a requirement, so every figure comes from one reproducible run. |
32
33
 
33
34
  ### Code Architecture
34
35
 
@@ -77,6 +78,14 @@ Skills for reviewing high-level architecture, messaging patterns, and data flow.
77
78
  | **composability-auditor** | McIlroy, Pike, Thompson (Unix Philosophy) | Identifies reuse blockers (hidden I/O, non-standard interfaces, statefulness) and decomposes self-sufficient units into composable pieces. |
78
79
  | **temporal-coupling-detector** | Beck, Fowler (software engineering canon) | Detects hidden ordering dependencies (two-phase init, method order, invisible preconditions) and enforces them through types, parameters, and factory patterns. |
79
80
 
81
+ ### Verification
82
+
83
+ Skills that check code does what it was meant to do, with evidence rather than opinion.
84
+
85
+ | Skill | Based on | What it does |
86
+ |-------|----------|--------------|
87
+ | **bug-hunter** | QA scenario testing; intent-first reproduction | Proves logic bugs with failing repros checked against stated intent. Writes scenarios before reading the code, and reports bugs, ambiguities, and covered scenarios. |
88
+
80
89
  ### Communication
81
90
 
82
91
  Skills that control how the agent communicates: output compression, token efficiency, and response style.
@@ -112,7 +121,7 @@ Skills that compose the other audit skills into higher-level workflows.
112
121
  | Skill | What it does |
113
122
  |-------|--------------|
114
123
  | **improve-my-codebase** | Runs every applicable audit skill in parallel against your codebase, ranks findings by convergence (multiple audits agreeing) and per-file rollup, and writes a prioritized improvement report. Default sweeps everything; positional args switch modes (`quick`, `diff`, `interactive`) or narrow scope (`focus <area>`, `module <path>`). |
115
- | **magpie** | Interactive PR review pipeline. Runs five parallel specialist subagents (security, bugs, performance, code-smells, architecture), dedupes findings, applies a critic rubric, peer-reviews via `codex exec`, and serves an interactive HTML report for selecting findings to post via `gh`. |
124
+ | **magpie** | Interactive PR review pipeline. Runs five parallel specialist subagents (security, bugs, performance, code-smells, architecture), dedupes findings, applies a critic rubric, peer-reviews via `codex exec`, and serves an interactive HTML report for selecting findings to post via `gh`. A local mode reviews the current branch diff before a PR exists and hands the findings back in the terminal. |
116
125
 
117
126
  ## Commands
118
127
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iceinvein/agent-skills",
3
- "version": "0.21.5",
3
+ "version": "0.23.0",
4
4
  "description": "Install agent skills into AI coding tools",
5
5
  "author": "iceinvein",
6
6
  "license": "MIT",
@@ -12,6 +12,7 @@
12
12
  "dist",
13
13
  "skills",
14
14
  "!skills/*/evals/results",
15
+ "!skills/*/evals/*/plugins",
15
16
  "!skills/terse/bench/results"
16
17
  ],
17
18
  "scripts": {
@@ -23,6 +24,8 @@
23
24
  "skill:bump:check": "bun run src/cli/index.ts bump --all --dry-run",
24
25
  "build:index": "bun run scripts/build-index.ts",
25
26
  "skill:audit": "bun run scripts/audit-skills.ts",
27
+ "eval:fresh": "bun run scripts/eval-freshness.ts",
28
+ "eval:plugins": "bun run scripts/eval-plugins.ts",
26
29
  "release": "bash scripts/release.sh"
27
30
  },
28
31
  "keywords": [
@@ -0,0 +1,87 @@
1
+ ---
2
+ name: bug-hunter
3
+ description: Use when asked to hunt for bugs or edge cases in a change or area, to say what QA will find before QA does, or to prove a change correct. Runs QA-style scenarios as failing reproductions in the repo's own test runner and reports only bugs it can prove, plus the questions intent leaves open.
4
+ ---
5
+
6
+ # Bug hunter
7
+
8
+ Agent-written code passes its own tests and still fails when QA hits a
9
+ scenario nobody wrote down. This skill runs the code and proves each bug with
10
+ a failing reproduction, checked against what the change was meant to do.
11
+
12
+ ## Method
13
+
14
+ 1. **Name the target** in one line: a diff (a commit, a range, the working
15
+ changes) or a set of paths. Every later step is scoped to it.
16
+ 2. **Collect intent** into `intent.md`: numbered claims (`I1`, `I2`, ...),
17
+ each one checkable statement with its source. Sources are the request or
18
+ ticket, commit messages, specs and designs, docs, `CLAUDE.md`/`AGENTS.md`,
19
+ invariants stated in unchanged code, sibling implementations the target
20
+ says it mirrors, and existing tests on unchanged code. Read the target's
21
+ code as much as you need, but a claim never comes from what a changed body
22
+ does: that is the code confirming itself.
23
+ 3. **Hunt.** Write scenarios the way QA would into `scenarios.md` (`S1`,
24
+ `S2`, ..., each with a one-line label, the expected result and the claim
25
+ it rests on), working through `references/scenario-catalog.md`, adding
26
+ more as the code and failures suggest. For each one worth trying write a
27
+ repro in the repo's own test framework that asserts the expected result.
28
+ Find the runner from the repo's manifests and `CLAUDE.md`/`AGENTS.md`; do
29
+ not install a test dependency. Favour many cheap probes over a few
30
+ elaborate ones, and chase what a failure suggests.
31
+ 4. **Check each failure before reporting it.** Run its repro alone, clean,
32
+ with only its own files, and confirm it fails with the observed value.
33
+ Confirm the repro tests the target and not its own setup: a mock returning
34
+ what the real dependency never would, or a fixture breaking an invariant
35
+ the caller guarantees, is not a bug.
36
+ 5. **Sort** each result with the rules below, and write the output.
37
+
38
+ Work in a scratch copy (a `git worktree`, or the copy the caller names). Never
39
+ modify the caller's tree: no repro, install or build artefact lands there.
40
+
41
+ ## What counts as a bug
42
+
43
+ No repro, no finding: a bug carries a reproduction that fails in a clean run
44
+ and names the claim it violates.
45
+
46
+ - **A concrete claim, contradicted,** is a bug citing that claim.
47
+ - **Claims have a rank.** The request, ticket, spec or design outranks a
48
+ docstring or comment inside the target's changed code, which is the change
49
+ describing itself. A target that follows its own docstring against the spec
50
+ is a bug citing the spec. Only claims of the same rank that disagree make an
51
+ ambiguity.
52
+ - **Some results are wrong under every reading,** and need no stated claim: a
53
+ crash, an error or a blank page from input the target accepts; a call that
54
+ reports success and did not do the work; an earlier action's result landing
55
+ over a later one's; a value shown in a form no reading allows, such as a
56
+ seconds field of 60; one user's data reaching or blocking another user. Add
57
+ the one you rely on to `intent.md` with source `baseline`.
58
+ - **An ambiguity is a question with more than one acceptable answer,** where
59
+ the code picked one and no claim says which: where a cap sits, whether a
60
+ match ignores case. "No spec says so" is not enough; if every acceptable
61
+ answer makes the observed result wrong, it is a bug.
62
+ - **Latent is not a bug.** A defect on a path no production caller reaches
63
+ today is noted in `report.md`, not filed in `bugs`.
64
+
65
+ ## Output
66
+
67
+ Write to `.bug-hunter/<YYYY-MM-DD>-<slug>/` at the repo root: `intent.md`,
68
+ `scenarios.md`, `report.md` for a human, and `findings.json` for a grader or calling skill,
69
+ in the shape `references/findings-format.md` gives. Three buckets: **bugs**
70
+ (scenario, violated claim, expected against observed, repro files and
71
+ command), **ambiguities** (the question for product), **covered** (scenarios
72
+ that passed, with the claim each checked). Write `findings.json` and
73
+ `report.md` with the Write tool, never from a shell command or script.
74
+
75
+ The `.bug-hunter/` directory is the one path in the caller's tree the skill
76
+ writes. Promoting a repro into the tree as a regression test is the caller's
77
+ job.
78
+
79
+ The directory ignores itself, so no repo has to add a line for it: if
80
+ `.bug-hunter/.gitignore` is absent, write it holding `*` before anything else
81
+ in the run. Leave an existing one alone; deleting it is how a repo chooses to
82
+ commit its runs.
83
+
84
+ ## Hand-back
85
+
86
+ The run directory, the counts per bucket, then each bug in one line:
87
+ scenario, violated claim, repro command. Name anything not done.
@@ -0,0 +1,287 @@
1
+ # bug-hunter evals
2
+
3
+ Seven cases for `claude plugin eval`. Each scaffolds a small Node repo with a
4
+ `SPEC.md`, one module and a passing `node --test` suite, committed in two steps
5
+ (the spec, then the module) so the target reads as a change. The prompt asks
6
+ what QA will find in the module, the way a user would, and never names the
7
+ skill.
8
+
9
+ | Case | Fixture | What it pins |
10
+ |---|---|---|
11
+ | `proves-a-spec-boundary-bug` | Usernames are 3 to 20 characters inclusive; the code rejects 20 | A bug in `findings.json` citing the limit, with a repro that fails against the fixture |
12
+ | `silent-spec-is-an-ambiguity` | Quantities are "capped"; the spec never says where, the code uses 99 | The cap lands in `ambiguities` and `bugs` is empty |
13
+ | `correct-code-has-no-bugs` | Pagination that meets every stated range at its edge | `bugs` is empty |
14
+ | `callers-tree-unchanged` | A backoff whose first delay is doubled | Nothing changes in the caller's tree outside `.bug-hunter/`, and `.bug-hunter/.gitignore` is written holding `*` |
15
+ | `bug-cites-intent-from-spec` | A coupon that floors where the spec rounds half up | `intent.md` is written, and the bug cites a claim sourced from `SPEC.md`, not from the code's floor |
16
+ | `spec-outranks-target-docstring` | The spec keeps a sealed export on offer when its rewrite fails; the module's docstring and code drop it | A bug citing the spec claim, not an ambiguity between spec and docstring |
17
+ | `impossible-value-is-a-bug` | The spec is silent on rounding; the code shows `60s` and `1m 60s` | A bug for the seconds field of 60, which no rounding rule gives |
18
+
19
+ Every case also has `bug-hunter-fired`, a `tool_used: Skill` grader, so a
20
+ score can be told apart from the model's own habits.
21
+
22
+ ## Running
23
+
24
+ From the repo root. Pin the model, because the eval child does not inherit
25
+ it, and pin the judge, because `--model` does not reach it:
26
+
27
+ ```bash
28
+ claude plugin eval skills/bug-hunter --scaffold --allow-tools Bash Write Edit \
29
+ --model claude-opus-5-5 --judge-model claude-opus-5-5 --runs 1 --ablation none
30
+ ```
31
+
32
+ Add `--keep-temp` to keep each run's sandbox and trace, which is the only way
33
+ to read back why a grader failed. `-j 7` runs the seven cases at once.
34
+
35
+ To check the skill against its last accepted baseline, use `eval:fresh`:
36
+
37
+ ```bash
38
+ bun run eval:fresh run skills/bug-hunter --model claude-opus-5-5
39
+ bun run eval:fresh diff skills/bug-hunter <result.json> [--against <model>]
40
+ bun run eval:fresh accept skills/bug-hunter <result.json>
41
+ ```
42
+
43
+ - `run` runs both arms on your Claude plan (default `--runs 3 -j 2`), then
44
+ diffs the result against `evals/baselines/<model>.json`.
45
+ - `diff` is free: it re-reads an existing result and runs nothing.
46
+ - `accept` writes the baseline. It is always a deliberate step, never part of
47
+ `run`.
48
+
49
+ What each verdict means is in `skills/sluice/evals/README.md`.
50
+ `callers-tree-unchanged` is listed in `vacuousWithout` in `rules.json`:
51
+ `tree-unchanged` passes on a run that writes nothing, so the no-plugin arm
52
+ scores on it without hunting, and the case is never called redundant or
53
+ skill-worse.
54
+
55
+ ## What the graders can and cannot see
56
+
57
+ The run directory is `.bug-hunter/<date>-<slug>/` and the slug is the skill's
58
+ choice. Only `file_exists` resolves a glob; a `regex` or `llm` grader pointed at
59
+ a file needs its exact path and throws on a glob. So:
60
+
61
+ - `findings-written` and `intent-written` read the harness's `files` target,
62
+ one created path per line, and match
63
+ `.bug-hunter/<YYYY-MM-DD>-<slug>/findings.json` (or `intent.md`) there. A
64
+ `file_exists` glob would accept a directory with no date; this holds the
65
+ prefix to the shape SKILL.md states, though not to the day the run ran.
66
+ - `written-with-write-tool` (in `silent-spec-is-an-ambiguity` and
67
+ `correct-code-has-no-bugs`) fails a Bash command that redirects or tees into
68
+ `intent.md`, `findings.json` or `report.md` under `.bug-hunter/`, which is
69
+ what holds the Write-tool rule: the content graders below read a heredoc's
70
+ JSON as readily as a Write call's. A script that opens the file itself
71
+ (`python3`, `node -e`) is not caught by it; the content graders fail that.
72
+ - Every grader that reads the *content* of `findings.json` reads the trace
73
+ instead: the Write tool call, or the shell command, that created it. The
74
+ regex graders (`bugs-empty`, `cap-is-an-ambiguity`) need the JSON to appear
75
+ there as a literal, which holds for a Write call or a heredoc. **They cannot
76
+ see a `findings.json` that a script builds** (`python3 -c` with `json.dump`,
77
+ `node -e` with `JSON.stringify`): the trace then holds the script, not the
78
+ JSON, and the grader fails whatever the file says. The baseline hit this.
79
+ Both judge only the **last** write of `findings.json`: a closing lookahead
80
+ fails the match if any later write of it follows (a Write, an Edit, or a
81
+ shell redirect). Before 0.2.1 they passed on any write, so an empty first
82
+ draft rewritten with bugs passed `bugs-empty`. A later Edit fails them,
83
+ since an Edit's trace entry does not carry the whole file.
84
+ - `bug-cites-the-limit` is an `llm` judge over the trace, so it can read a
85
+ script that builds the file as well as a literal. It sees a head-and-tail
86
+ window of a long trace (about 80k characters of head, 20k of tail), so a
87
+ findings write that lands in the dropped middle is invisible to it. It cannot
88
+ run the repro; "fails in the fixture" is judged against the fixture's code,
89
+ which the rubric quotes. Its rubric also says to judge only the last write.
90
+ - `tree-unchanged` cannot run `git status --porcelain`. It reads the harness's
91
+ `files` target, the list of paths the run created in its working directory,
92
+ and fails on any path outside `.bug-hunter/` or `.git/`. A file `.gitignore`
93
+ hides still counts. The `files` target never lists a file the run only
94
+ modified, so on its own it passes an edit to the scaffold's files.
95
+ `source-unchanged` fails if the buggy line in `src/backoff.js` was
96
+ rewritten, and `tests-unchanged` if `tests/backoff.test.js` gained a test.
97
+ An edit to `package.json` or `SPEC.md` is still unseen. A run that writes
98
+ nothing passes all three, which is why the case also has
99
+ `bug-hunter-fired`.
100
+ - `output-ignores-itself` in the same case reads the trace for a Write of
101
+ `.bug-hunter/.gitignore` whose content is `*`, or a shell command that
102
+ writes a `*` into it. The `files` target would show the path but not its
103
+ content, and an empty `.gitignore` ignores nothing. A script that opens the
104
+ file itself is not caught.
105
+ - `bug-cites-the-spec` in `bug-cites-intent-from-spec` is an `llm` judge over
106
+ the trace, with the same window and last-write limits as
107
+ `bug-cites-the-limit`. It resolves the bug's `claim` through the `intent`
108
+ array and fails a claim sourced from `src/discount.js`. It cannot tell a
109
+ claim the skill read out of the body but labelled `SPEC.md`; the spec's
110
+ wording ("half cent rounding up") is what makes such a mislabel visible to
111
+ it. This case replaced `scenarios-before-bodies` in 0.4.0, which pinned the
112
+ scenario-before-body order that 0.4.0 dropped.
113
+
114
+ ## Baseline
115
+
116
+ ### Skill 0.4.0, Opus 5.5, 2026-10-13
117
+
118
+ Same command, `-j 7`. Skill 0.4.0 drops the three dispatched roles for one
119
+ agent that may read the code freely, keeping intent collection, the scenario
120
+ catalog, a clean re-run of each failure and the 0.3.0 rules, and reporting
121
+ latent defects without filing them. It is the `variants/thin` arm of the
122
+ pilot benchmark, which proved or judged 3 of 12 answer keys against 2 for the
123
+ plain baseline and 2 for 0.3.0, with every extra finding triaged real, at USD
124
+ 1.83 a run against 3.19 for 0.3.0. USD 3.74 in all, 102s,
125
+ `results/2026-10-13T03-48-17-313Z`. Overall 1.00. One run per case.
126
+
127
+ | Case | 0.3.0 | 0.4.0 | USD (0.4.0) |
128
+ |---|---|---|---|
129
+ | `proves-a-spec-boundary-bug` | 1.00 | 1.00 | 0.77 |
130
+ | `silent-spec-is-an-ambiguity` | 1.00 | 1.00 | 0.44 |
131
+ | `correct-code-has-no-bugs` | 1.00 | 1.00 | 0.34 |
132
+ | `callers-tree-unchanged` | 1.00 | 1.00 | 0.43 |
133
+ | `scenarios-before-bodies` | 1.00 | 1.00 | 0.49 |
134
+ | `spec-outranks-target-docstring` | 1.00 | 1.00 | 0.58 |
135
+ | `impossible-value-is-a-bug` | 1.00 | 1.00 | 0.70 |
136
+
137
+ `scenarios-before-bodies` passed, but 0.4.0 no longer asks for that order: the
138
+ run happened to write `scenarios.md` before reading `src/discount.js`. The case
139
+ pinned a rule the skill dropped, so it was rewritten as
140
+ `bug-cites-intent-from-spec` on the same fixture.
141
+
142
+ ### Skill 0.3.0, Opus 5.5, 2026-10-12
143
+
144
+ Same command, `-j 7`. Skill 0.3.0 ranks claims (a spec, design or request
145
+ outranks a docstring in the changed code), lets a result wrong under every
146
+ reading count as a bug against a `baseline` claim, and keeps ambiguities for
147
+ questions with more than one acceptable answer. It answers the pilot
148
+ benchmark, where 0.2.1 filed two real defects it had reproduced as
149
+ ambiguities. USD 6.55 in all, 228s, `results/2026-10-12T14-46-50-101Z`.
150
+ Overall 1.00. One run per case.
151
+
152
+ The two new cases also scored 1.00 on 0.2.1 (USD 0.91 and 1.07,
153
+ `results/2026-10-12T14-43-31-*`): at fixture size the conflict is plain enough
154
+ that the old rules got it right, so neither reproduces the pilot's miss. They
155
+ stay as guards against the opposite failure. The cases that pin over-reporting,
156
+ `silent-spec-is-an-ambiguity` and `correct-code-has-no-bugs`, still hold on
157
+ 0.3.0: the cap stays a question and the correct module has no bugs.
158
+
159
+ | Case | 0.2.1 | 0.3.0 | USD (0.3.0) |
160
+ |---|---|---|---|
161
+ | `proves-a-spec-boundary-bug` | 1.00 | 1.00 | 1.29 |
162
+ | `silent-spec-is-an-ambiguity` | 1.00 | 1.00 | 1.07 |
163
+ | `correct-code-has-no-bugs` | 1.00 | 1.00 | 0.69 |
164
+ | `callers-tree-unchanged` | 1.00 | 1.00 | 0.62 |
165
+ | `scenarios-before-bodies` | 1.00 | 1.00 | 0.65 |
166
+ | `spec-outranks-target-docstring` | 1.00 | 1.00 | 1.35 |
167
+ | `impossible-value-is-a-bug` | 1.00 | 1.00 | 0.88 |
168
+
169
+ ### Skill 0.2.1, Opus 5.5, 2026-10-12
170
+
171
+ Same command as 0.2.0 below. Skill 0.2.1 writes each findings `scenario` as
172
+ `"<id>: <label>"`, lets the single-agent fallback add a late claim from a
173
+ source other than the changed body, and the `findings.json` graders now judge
174
+ only the last write. USD 5.39 in all, 361s,
175
+ `results/2026-10-12T09-23-52-868Z`. Overall 1.00. One run per case.
176
+
177
+ | Case | 0.2.0 | 0.2.1 | USD (0.2.1) | Reading |
178
+ |---|---|---|---|---|
179
+ | `proves-a-spec-boundary-bug` | 1.00 | 1.00 | 1.01 | Judge PASS PASS PASS. `B1` is `"S2: a 20-character name is accepted"`, citing I1 |
180
+ | `silent-spec-is-an-ambiguity` | 1.00 | 1.00 | 1.04 | One `findings.json` Write, `bugs` empty; the cap question is `"S13: Quantity exactly at the cap, one below and one above"` |
181
+ | `correct-code-has-no-bugs` | 1.00 | 1.00 | 1.03 | One Write, `bugs` empty, 16 covered, two ambiguities (numeric strings, `Infinity`) |
182
+ | `callers-tree-unchanged` | 1.00 | 1.00 | 0.70 | No path outside `.bug-hunter/` changed |
183
+ | `scenarios-before-bodies` | 1.00 | 1.00 | 1.61 | Scenario author dispatched; `scenarios.md` written before any Read of `src/discount.js` |
184
+
185
+ Every `scenario` in every bucket of all five runs carried its label. Every
186
+ run wrote `findings.json` once, so the last-write rule changed no verdict
187
+ here; it was checked on doctored copies of the 0.2.0 traces (an empty draft
188
+ followed by a write with bugs, a later Edit, a later heredoc), where the old
189
+ patterns passed and the new ones fail. Every run dispatched at least one role
190
+ and wrote `intent.md` once, so the fallback's late-claim rule was not
191
+ exercised; no fixture has a sibling implementation or a stated invariant.
192
+
193
+ ### Skill 0.2.0, Opus 5.5, 2026-10-12
194
+
195
+ Same command plus `--trust-plugin --no-publish`, CLI 2.1.296. Skill 0.2.0
196
+ counts intent stated in the repo itself (invariants the code states, sibling
197
+ implementations it says it mirrors, existing tests, docs) and requires
198
+ `findings.json` and `report.md` to be written with the Write tool. USD 5.08 in
199
+ all (judging USD 0.40), 265s, `results/2026-10-12T07-49-17-746Z`. Overall
200
+ 1.00, against 0.84 for 0.1.0 below. One run per case, so every score is a
201
+ single sample.
202
+
203
+ | Case | 0.1.0 | 0.2.0 | USD (0.2.0) | Reading |
204
+ |---|---|---|---|---|
205
+ | `proves-a-spec-boundary-bug` | 1.00 | 1.00 | 1.33 | Judge PASS PASS PASS |
206
+ | `silent-spec-is-an-ambiguity` | 0.20 | 1.00 | 1.12 | `findings.json` written with Write, so both regexes see it. `bugs` empty; `A1` asks what the cap is and names the code's 99 |
207
+ | `correct-code-has-no-bugs` | 1.00 | 1.00 | 0.38 | `bugs` empty, 13 covered, one ambiguity (sparse arrays, which `SPEC.md` does not address) |
208
+ | `callers-tree-unchanged` | 1.00 | 1.00 | 1.17 | No path outside `.bug-hunter/` changed |
209
+ | `scenarios-before-bodies` | 1.00 | 1.00 | 1.08 | The dispatched scenario author wrote `scenarios.md` before any Read of `src/discount.js` |
210
+
211
+ No failures. The 0.1.0 failure is closed by the Write rule, not by a grader
212
+ change: all five runs wrote both files with the Write tool. The new intent
213
+ rule did not promote anything in the two cases it could have over-promoted:
214
+ the ambiguity run's five questions all stay ambiguities with `bugs` empty, and
215
+ the correct-code run's one open question (sparse arrays) stays an ambiguity.
216
+ None of the five fixtures has a sibling implementation or a stated invariant,
217
+ so these cases do not exercise the new confirm path; they only show it does
218
+ not leak into silent-spec cases.
219
+
220
+ Dispatch is still not reliable. The correct-code run ran all three roles in
221
+ the main thread with the Agent tool available (70s, the cheapest run); its
222
+ `intent.md` and `scenarios.md` were on disk before it ran `cat` on
223
+ `src/paginate.js`, so the fallback's order held. It hunted in a `$TMPDIR` copy
224
+ rather than a git worktree. The ambiguity run dispatched the scenario author
225
+ and executor and no refuter, which fits: no repro failed.
226
+
227
+ ### Skill 0.1.0, Opus 5.5, 2026-10-12
228
+
229
+ CLI 2.1.296, `--model claude-opus-5-5 --judge-model claude-opus-5-5 --runs 1
230
+ --ablation none --keep-temp -j 5`. One run per case, so every score is a single
231
+ sample. USD 5.30 in all (judging USD 0.39), 317s,
232
+ `results/2026-10-12T05-33-00-761Z`. Overall 0.84, four of five cases at 1.00.
233
+
234
+ | Case | Score | USD | Reading |
235
+ |---|---|---|---|
236
+ | `proves-a-spec-boundary-bug` | 1.00 | 0.77 | Judge PASS PASS PASS. One bug citing I1 (3 to 20 inclusive) with a repro asserting a 20-character name is accepted |
237
+ | `silent-spec-is-an-ambiguity` | 0.20 | 0.97 | `bugs-empty` and `cap-is-an-ambiguity` fail on the grader's blind spot, not the skill (below) |
238
+ | `correct-code-has-no-bugs` | 1.00 | 0.98 | `bugs` empty; findings written with the Write tool |
239
+ | `callers-tree-unchanged` | 1.00 | 1.19 | No path outside `.bug-hunter/` changed; a look at the kept sandbox agrees |
240
+ | `scenarios-before-bodies` | 1.00 | 1.39 | The scenario author (a dispatched agent) wrote `scenarios.md`; the first Read of `src/discount.js` came later |
241
+
242
+ **`silent-spec-is-an-ambiguity` failed, and the skill did what the case
243
+ asks.** The run wrote `findings.json` with `python3 -I -` and `json.dump`, so
244
+ the trace holds a Python list, not the JSON the two regexes look for; both
245
+ report "pattern not found in trace". The file kept in the sandbox has
246
+ `"bugs": []` and, first among five ambiguities, `A1`: "What is the cap?
247
+ SPEC.md never gives a number; the code uses 99 (MAX_QUANTITY). Is 99 the
248
+ intended value, and should the spec say so?" The final message says the same.
249
+ The graders stay as written. The fix is not to widen them: either the skill
250
+ writes `findings.json` with the Write tool, which `findings-format.md` does not
251
+ ask for today, or the harness lets a file target take a glob. Which one is
252
+ open.
253
+
254
+ **Other things the traces show, which no grader scores.**
255
+
256
+ - Dispatch is not reliable. Four of the five baseline runs (ambiguity,
257
+ correct, tree, order) dispatched the scenario author, executor and refuter
258
+ as separate agents. The boundary-bug run, and the sanity run of the same
259
+ case before it, ran all three roles in the main thread with the Agent tool
260
+ available, which the skill reserves for when dispatch is unavailable. In
261
+ both, `intent.md` and `scenarios.md` were on disk before the body was read,
262
+ so the fallback's order held.
263
+ - Git inside the eval sandbox: a bare `git` is Apple's xcrun shim, which fails
264
+ there (as in `skills/sluice/evals/README.md`), and so does the checkout step
265
+ of `git worktree add` even from `/opt/homebrew/bin/git`. The tree run worked
266
+ around it with `worktree add --no-checkout` then `reset --hard`, so it hunted
267
+ in a real scratch worktree and removed it after; its own closing
268
+ `git status --short` showed only `?? .bug-hunter/`. The order run fell back
269
+ to `git archive` into `$TMPDIR`, and the boundary-bug, ambiguity and correct
270
+ runs copied the files into `$TMPDIR` without git. The caller's tree stayed
271
+ clean either way, but the skill's scratch worktree held the repros in one
272
+ run of five.
273
+ - Before writing scenarios, the order run's main thread ran Grep with content
274
+ output over `src/discount.js` for `export` and comment lines. That shows
275
+ declaration lines, which the skill allows, but the same call shape could
276
+ show a body, and the order grader does not count it.
277
+
278
+ **Sanity run before the baseline.** `proves-a-spec-boundary-bug` alone (USD
279
+ 0.79, `results/2026-10-12T05-30-48-463Z`): 1.00. Its trace was then used to
280
+ check that each regex grader can fail. `scenarios-before-bodies`, pointed at
281
+ `src/username.js`, matched the real trace and did not match a copy with the
282
+ body's Read moved ahead of the `scenarios.md` write. `bugs-empty` and
283
+ `cap-is-an-ambiguity` did not match the real findings write (one bug, no
284
+ ambiguities) and did match a copy with `bugs` emptied and a cap question added.
285
+ `tree-unchanged` passed on a listing of only `.bug-hunter/` paths and failed
286
+ once `tests/backoff-hunt.test.js` was added. The `llm` grader's FAIL path was
287
+ not exercised: both runs of its case found the bug.
@@ -0,0 +1,93 @@
1
+ {
2
+ "model": "claude-opus-5-5",
3
+ "judgeModel": "claude-opus-5-5",
4
+ "claudeVersion": "2.1.300",
5
+ "skillVersion": "0.4.0",
6
+ "date": "2026-10-15T13:04:21.155Z",
7
+ "cases": {
8
+ "bug-cites-intent-from-spec": {
9
+ "with": [
10
+ 1,
11
+ 1,
12
+ 1
13
+ ],
14
+ "without": [
15
+ 0,
16
+ 0,
17
+ 0
18
+ ]
19
+ },
20
+ "callers-tree-unchanged": {
21
+ "with": [
22
+ 1,
23
+ 1,
24
+ 1
25
+ ],
26
+ "without": [
27
+ 1,
28
+ 1,
29
+ 1
30
+ ]
31
+ },
32
+ "correct-code-has-no-bugs": {
33
+ "with": [
34
+ 1,
35
+ 1,
36
+ 1
37
+ ],
38
+ "without": [
39
+ 0.5,
40
+ 0.5,
41
+ 0.5
42
+ ]
43
+ },
44
+ "impossible-value-is-a-bug": {
45
+ "with": [
46
+ 1,
47
+ 1,
48
+ 1
49
+ ],
50
+ "without": [
51
+ 0,
52
+ 0,
53
+ 0
54
+ ]
55
+ },
56
+ "proves-a-spec-boundary-bug": {
57
+ "with": [
58
+ 1,
59
+ 1,
60
+ 1
61
+ ],
62
+ "without": [
63
+ 0,
64
+ 0,
65
+ 0
66
+ ]
67
+ },
68
+ "silent-spec-is-an-ambiguity": {
69
+ "with": [
70
+ 1,
71
+ 1,
72
+ 1
73
+ ],
74
+ "without": [
75
+ 0.3333333333333333,
76
+ 0.3333333333333333,
77
+ 0.3333333333333333
78
+ ]
79
+ },
80
+ "spec-outranks-target-docstring": {
81
+ "with": [
82
+ 1,
83
+ 1,
84
+ 1
85
+ ],
86
+ "without": [
87
+ 0,
88
+ 0,
89
+ 0
90
+ ]
91
+ }
92
+ }
93
+ }
@@ -0,0 +1,4 @@
1
+ schema_version: "1.1"
2
+ name: bug-cites-intent-from-spec
3
+ context:
4
+ scaffold_script: fixture.sh
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env bash
2
+ # A coupon helper whose only bug is in its rounding (the spec says halves
3
+ # round up, the code floors). The case is about where the expected value comes
4
+ # from: the bug has to cite a claim intent.md took from SPEC.md, not one read
5
+ # out of the floor in src/discount.js, which would confirm the code against
6
+ # itself.
7
+ set -euo pipefail
8
+
9
+ mkdir -p src tests
10
+
11
+ cat > package.json <<'JSON'
12
+ {
13
+ "name": "checkout",
14
+ "version": "3.1.0",
15
+ "type": "module",
16
+ "scripts": {
17
+ "test": "node --test \"tests/*.test.js\""
18
+ }
19
+ }
20
+ JSON
21
+
22
+ cat > SPEC.md <<'MD'
23
+ # Checkout coupons
24
+
25
+ `applyCoupon(totalCents, coupon)` in `src/discount.js` returns the order total
26
+ after a percentage coupon, in cents.
27
+
28
+ - `totalCents` is a whole number of 0 or more; anything else throws a
29
+ `RangeError`.
30
+ - A coupon is `{ percentOff }`, where `percentOff` is a whole number from 1 to
31
+ 100, inclusive; anything else throws a `RangeError`.
32
+ - The result is the total less `percentOff` percent, rounded to the nearest
33
+ cent, with a half cent rounding up.
34
+ MD
35
+
36
+ git init --quiet
37
+ git add -A
38
+ git -c user.email=fixture@example.com -c user.name=fixture commit --quiet -m "spec: checkout coupons"
39
+
40
+ cat > src/discount.js <<'JS'
41
+ export function applyCoupon(totalCents, coupon) {
42
+ if (!Number.isInteger(totalCents) || totalCents < 0) {
43
+ throw new RangeError(`totalCents must be a whole number of 0 or more, got ${totalCents}`);
44
+ }
45
+
46
+ const percentOff = coupon?.percentOff;
47
+
48
+ if (!Number.isInteger(percentOff) || percentOff < 1 || percentOff > 100) {
49
+ throw new RangeError(`percentOff must be a whole number from 1 to 100, got ${percentOff}`);
50
+ }
51
+
52
+ return Math.floor((totalCents * (100 - percentOff)) / 100);
53
+ }
54
+ JS
55
+
56
+ cat > tests/discount.test.js <<'JS'
57
+ import assert from "node:assert/strict";
58
+ import { test } from "node:test";
59
+ import { applyCoupon } from "../src/discount.js";
60
+
61
+ test("ten percent off a round total", () => {
62
+ assert.equal(applyCoupon(10000, { percentOff: 10 }), 9000);
63
+ });
64
+
65
+ test("a coupon over 100 percent throws", () => {
66
+ assert.throws(() => applyCoupon(10000, { percentOff: 101 }), RangeError);
67
+ });
68
+ JS
69
+
70
+ git add -A
71
+ git -c user.email=fixture@example.com -c user.name=fixture commit --quiet -m "feat: apply percentage coupons at checkout"
@@ -0,0 +1,36 @@
1
+ ---
2
+ type: llm
3
+ # As in proves-a-spec-boundary-bug: the judge cannot run the repro, so "fails
4
+ # in the fixture" is judged against the fixture's code, quoted below, and it
5
+ # reads the trace because findings.json sits under a slug no file focus names.
6
+ focus: trace
7
+ weight: 3
8
+ ---
9
+
10
+ The agent was asked what QA will find in `src/discount.js`, going by
11
+ `SPEC.md`. `SPEC.md` says the result is the total less `percentOff` percent,
12
+ "rounded to the nearest cent, with a half cent rounding up". The fixture's
13
+ code floors instead:
14
+
15
+ ```js
16
+ return Math.floor((totalCents * (100 - percentOff)) / 100);
17
+ ```
18
+
19
+ So `applyCoupon(1005, { percentOff: 10 })` returns `904` (904.5 floored)
20
+ where the spec requires `905`, and any result with a fractional part of a
21
+ half cent or more is a cent short. Nothing else in the code departs from the
22
+ spec.
23
+
24
+ Find the `findings.json` the agent wrote under `.bug-hunter/` (its content
25
+ appears in a Write tool call or a shell command in the trace). If it was
26
+ written more than once, judge only the last write, with any later Edit to it
27
+ applied.
28
+
29
+ PASS if its `bugs` array has an entry whose `claim` resolves, through the
30
+ `intent` array, to a claim whose `source` is `SPEC.md` and which states the
31
+ round-to-nearest, half-up rule, and whose `repro` asserts a half-up rounded
32
+ result that the flooring code above does not give, so that it fails.
33
+ FAIL if no findings.json content is visible in the trace, if `bugs` is empty,
34
+ if the bug's claim resolves to an intent entry whose source is
35
+ `src/discount.js` or that describes the floor as intended, or if the repro
36
+ asserts something the code above already does.
@@ -0,0 +1,5 @@
1
+ ---
2
+ type: tool_used
3
+ tool: Skill
4
+ input_match: '"skill"\s*:\s*"(?:[\w-]+:)?bug-hunter"'
5
+ ---
@@ -0,0 +1,8 @@
1
+ ---
2
+ type: regex
3
+ # As findings-written in proves-a-spec-boundary-bug: the files target holds
4
+ # the run directory's date prefix to the shape SKILL.md states.
5
+ pattern: '^\.bug-hunter/\d{4}-\d{2}-\d{2}-[^/]+/intent\.md$'
6
+ flags: m
7
+ target: files
8
+ ---
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: bug-cites-intent-from-spec
3
+ description: The skill may read the code, but a claim never comes from what a changed body does. Pins the rounding bug citing an intent claim sourced from SPEC.md, with a repro expecting half-up rounding.
4
+ tags: [intent, arithmetic, scaffold, write]
5
+ max_turns: 80
6
+ timeout_seconds: 2400
7
+ allowed_tools: [Read, Glob, Grep, Skill, Write, Edit, Bash, Agent]
8
+ expected_outcome: intent.md exists, and findings.json under .bug-hunter/ has a bug whose claim resolves to SPEC.md's half-cent-rounds-up rule, with a repro that fails against the flooring code.
9
+ ---
10
+
11
+ What will QA find in `src/discount.js`, going by `SPEC.md`?