@iceinvein/agent-skills 0.21.5 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/package.json +4 -1
- package/skills/bug-hunter/SKILL.md +82 -0
- package/skills/bug-hunter/evals/README.md +282 -0
- package/skills/bug-hunter/evals/baselines/claude-opus-5-5.json +93 -0
- package/skills/bug-hunter/evals/bug-cites-intent-from-spec/case.yaml +4 -0
- package/skills/bug-hunter/evals/bug-cites-intent-from-spec/fixture.sh +71 -0
- package/skills/bug-hunter/evals/bug-cites-intent-from-spec/graders/bug-cites-the-spec.md +36 -0
- package/skills/bug-hunter/evals/bug-cites-intent-from-spec/graders/bug-hunter-fired.md +5 -0
- package/skills/bug-hunter/evals/bug-cites-intent-from-spec/graders/intent-written.md +8 -0
- package/skills/bug-hunter/evals/bug-cites-intent-from-spec/prompt.md +11 -0
- package/skills/bug-hunter/evals/callers-tree-unchanged/case.yaml +4 -0
- package/skills/bug-hunter/evals/callers-tree-unchanged/fixture.sh +67 -0
- package/skills/bug-hunter/evals/callers-tree-unchanged/graders/bug-hunter-fired.md +5 -0
- package/skills/bug-hunter/evals/callers-tree-unchanged/graders/source-unchanged.md +10 -0
- package/skills/bug-hunter/evals/callers-tree-unchanged/graders/tests-unchanged.md +10 -0
- package/skills/bug-hunter/evals/callers-tree-unchanged/graders/tree-unchanged.md +15 -0
- package/skills/bug-hunter/evals/callers-tree-unchanged/prompt.md +11 -0
- package/skills/bug-hunter/evals/correct-code-has-no-bugs/case.yaml +4 -0
- package/skills/bug-hunter/evals/correct-code-has-no-bugs/fixture.sh +82 -0
- package/skills/bug-hunter/evals/correct-code-has-no-bugs/graders/bug-hunter-fired.md +5 -0
- package/skills/bug-hunter/evals/correct-code-has-no-bugs/graders/bugs-empty.md +18 -0
- package/skills/bug-hunter/evals/correct-code-has-no-bugs/graders/written-with-write-tool.md +13 -0
- package/skills/bug-hunter/evals/correct-code-has-no-bugs/prompt.md +11 -0
- package/skills/bug-hunter/evals/impossible-value-is-a-bug/case.yaml +4 -0
- package/skills/bug-hunter/evals/impossible-value-is-a-bug/fixture.sh +68 -0
- package/skills/bug-hunter/evals/impossible-value-is-a-bug/graders/bug-for-sixty-seconds.md +37 -0
- package/skills/bug-hunter/evals/impossible-value-is-a-bug/graders/bug-hunter-fired.md +5 -0
- package/skills/bug-hunter/evals/impossible-value-is-a-bug/prompt.md +11 -0
- package/skills/bug-hunter/evals/proves-a-spec-boundary-bug/case.yaml +4 -0
- package/skills/bug-hunter/evals/proves-a-spec-boundary-bug/fixture.sh +79 -0
- package/skills/bug-hunter/evals/proves-a-spec-boundary-bug/graders/bug-cites-the-limit.md +31 -0
- package/skills/bug-hunter/evals/proves-a-spec-boundary-bug/graders/bug-hunter-fired.md +5 -0
- package/skills/bug-hunter/evals/proves-a-spec-boundary-bug/graders/findings-written.md +10 -0
- package/skills/bug-hunter/evals/proves-a-spec-boundary-bug/prompt.md +11 -0
- package/skills/bug-hunter/evals/rules.json +177 -0
- package/skills/bug-hunter/evals/silent-spec-is-an-ambiguity/case.yaml +4 -0
- package/skills/bug-hunter/evals/silent-spec-is-an-ambiguity/fixture.sh +97 -0
- package/skills/bug-hunter/evals/silent-spec-is-an-ambiguity/graders/bug-hunter-fired.md +5 -0
- package/skills/bug-hunter/evals/silent-spec-is-an-ambiguity/graders/bugs-empty.md +18 -0
- package/skills/bug-hunter/evals/silent-spec-is-an-ambiguity/graders/cap-is-an-ambiguity.md +12 -0
- package/skills/bug-hunter/evals/silent-spec-is-an-ambiguity/graders/written-with-write-tool.md +13 -0
- package/skills/bug-hunter/evals/silent-spec-is-an-ambiguity/prompt.md +11 -0
- package/skills/bug-hunter/evals/spec-outranks-target-docstring/case.yaml +4 -0
- package/skills/bug-hunter/evals/spec-outranks-target-docstring/fixture.sh +82 -0
- package/skills/bug-hunter/evals/spec-outranks-target-docstring/graders/bug-cites-the-spec.md +40 -0
- package/skills/bug-hunter/evals/spec-outranks-target-docstring/graders/bug-hunter-fired.md +5 -0
- package/skills/bug-hunter/evals/spec-outranks-target-docstring/prompt.md +11 -0
- package/skills/bug-hunter/references/findings-format.md +82 -0
- package/skills/bug-hunter/references/scenario-catalog.md +92 -0
- package/skills/bug-hunter/skill.json +24 -0
- package/skills/index.json +17 -5
- package/skills/magpie/evals/README.md +13 -0
- package/skills/magpie/evals/baselines/claude-opus-5-5.json +69 -0
- package/skills/magpie/evals/rules.json +192 -0
- package/skills/magpie/skill.json +1 -1
- package/skills/migrate/evals/README.md +13 -0
- package/skills/migrate/evals/baselines/claude-opus-5-5.json +129 -0
- package/skills/migrate/evals/rules.json +160 -0
- package/skills/migrate/skill.json +10 -4
- package/skills/scope-estimate/README.md +173 -0
- package/skills/scope-estimate/SKILL.md +168 -0
- package/skills/scope-estimate/references/capability-map.md +122 -0
- package/skills/scope-estimate/references/deliverables.md +60 -0
- package/skills/scope-estimate/references/requirements.md +104 -0
- package/skills/scope-estimate/references/schedule.md +138 -0
- package/skills/scope-estimate/scripts/__tests__/schedule.test.ts +366 -0
- package/skills/scope-estimate/scripts/schedule.ts +553 -0
- package/skills/scope-estimate/skill.json +19 -0
- package/skills/scope-estimate/templates/plan.example.json +33 -0
- package/skills/sluice/SKILL.md +17 -3
- package/skills/sluice/evals/README.md +111 -6
- package/skills/sluice/evals/announcement-reaches-the-ledger/fixture.sh +32 -19
- package/skills/sluice/evals/announcement-reaches-the-ledger/graders/routes-main-before-source.md +14 -0
- package/skills/sluice/evals/announcement-reaches-the-ledger/prompt.md +2 -2
- package/skills/sluice/evals/baselines/claude-opus-5-5.json +237 -0
- package/skills/sluice/evals/deep-run-blocks-on-a-real-decision/fixture.sh +19 -12
- package/skills/sluice/evals/deep-run-fans-out/graders/task-1-merged-back.md +8 -0
- package/skills/sluice/evals/deep-run-fans-out/graders/task-2-merged-back.md +8 -0
- package/skills/sluice/evals/deep-run-fans-out/graders/task-3-merged-back.md +6 -0
- package/skills/sluice/evals/deep-run-fans-out/graders/worktree-per-implementer.md +12 -0
- package/skills/sluice/evals/deep-run-hunts-after-the-flip/case.yaml +5 -0
- package/skills/sluice/evals/deep-run-hunts-after-the-flip/fixture.sh +258 -0
- package/skills/sluice/evals/deep-run-hunts-after-the-flip/graders/bug-hunter-fired.md +5 -0
- package/skills/sluice/evals/deep-run-hunts-after-the-flip/graders/four-attempts-allowed.md +34 -0
- package/skills/sluice/evals/deep-run-hunts-after-the-flip/graders/fourth-attempt-tested.md +20 -0
- package/skills/sluice/evals/deep-run-hunts-after-the-flip/graders/hunt-before-the-final-review.md +21 -0
- package/skills/sluice/evals/deep-run-hunts-after-the-flip/graders/record-has-a-hunt-section.md +11 -0
- package/skills/sluice/evals/deep-run-hunts-after-the-flip/graders/sluice-fired.md +5 -0
- package/skills/sluice/evals/deep-run-hunts-after-the-flip/prompt.md +12 -0
- package/skills/sluice/evals/deep-run-survives-a-milestone/fixture.sh +46 -24
- package/skills/sluice/evals/fast-verifies-before-handback/case.yaml +4 -0
- package/skills/sluice/evals/fast-verifies-before-handback/fixture.sh +73 -0
- package/skills/sluice/evals/fast-verifies-before-handback/graders/quiet-flag-implemented.md +5 -0
- package/skills/sluice/evals/fast-verifies-before-handback/graders/sluice-fired.md +5 -0
- package/skills/sluice/evals/fast-verifies-before-handback/graders/verified-after-the-last-edit.md +18 -0
- package/skills/sluice/evals/fast-verifies-before-handback/prompt.md +11 -0
- package/skills/sluice/evals/main-hunts-a-checkable-claim/case.yaml +5 -0
- package/skills/sluice/evals/main-hunts-a-checkable-claim/fixture.sh +64 -0
- package/skills/sluice/evals/main-hunts-a-checkable-claim/graders/announces-main-channel.md +12 -0
- package/skills/sluice/evals/main-hunts-a-checkable-claim/graders/bug-hunter-fired.md +5 -0
- package/skills/sluice/evals/main-hunts-a-checkable-claim/graders/hunt-after-the-source-edits.md +12 -0
- package/skills/sluice/evals/main-hunts-a-checkable-claim/graders/last-page-holds-the-remainder.md +27 -0
- package/skills/sluice/evals/main-hunts-a-checkable-claim/graders/remainder-page-tested.md +21 -0
- package/skills/sluice/evals/main-hunts-a-checkable-claim/graders/sluice-fired.md +5 -0
- package/skills/sluice/evals/main-hunts-a-checkable-claim/prompt.md +12 -0
- package/skills/sluice/evals/main-new-interface/graders/shape-agreed-before-building.md +8 -4
- package/skills/sluice/evals/main-skips-the-hunt-without-a-claim/case.yaml +5 -0
- package/skills/sluice/evals/main-skips-the-hunt-without-a-claim/fixture.sh +73 -0
- package/skills/sluice/evals/main-skips-the-hunt-without-a-claim/graders/announces-main-channel.md +12 -0
- package/skills/sluice/evals/main-skips-the-hunt-without-a-claim/graders/no-hunt.md +12 -0
- package/skills/sluice/evals/main-skips-the-hunt-without-a-claim/graders/skip-said-in-one-line.md +21 -0
- package/skills/sluice/evals/main-skips-the-hunt-without-a-claim/graders/sluice-fired.md +5 -0
- package/skills/sluice/evals/main-skips-the-hunt-without-a-claim/prompt.md +12 -0
- package/skills/sluice/evals/rules.json +364 -0
- package/skills/sluice/references/deep-channel.md +48 -6
- package/skills/sluice/references/finish.md +5 -0
- package/skills/sluice/references/review.md +32 -0
- package/skills/sluice/references/status.md +17 -4
- package/skills/sluice/references/verify.md +38 -0
- package/skills/sluice/scripts/content-digest.sh +65 -0
- package/skills/sluice/scripts/run-stats.sh +9 -8
- package/skills/sluice/scripts/status.sh +78 -13
- package/skills/sluice/scripts/stop-guard.sh +97 -24
- package/skills/sluice/skill.json +2 -2
- package/skills/terse/evals/README.md +16 -0
- package/skills/terse/evals/baselines/claude-opus-5-5.json +105 -0
- package/skills/terse/evals/rules.json +161 -0
- package/skills/terse/skill.json +1 -1
- 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.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iceinvein/agent-skills",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.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,82 @@
|
|
|
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
|
+
## Hand-back
|
|
80
|
+
|
|
81
|
+
The run directory, the counts per bucket, then each bug in one line:
|
|
82
|
+
scenario, violated claim, repro command. Name anything not done.
|
|
@@ -0,0 +1,282 @@
|
|
|
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/` |
|
|
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
|
+
- `bug-cites-the-spec` in `bug-cites-intent-from-spec` is an `llm` judge over
|
|
101
|
+
the trace, with the same window and last-write limits as
|
|
102
|
+
`bug-cites-the-limit`. It resolves the bug's `claim` through the `intent`
|
|
103
|
+
array and fails a claim sourced from `src/discount.js`. It cannot tell a
|
|
104
|
+
claim the skill read out of the body but labelled `SPEC.md`; the spec's
|
|
105
|
+
wording ("half cent rounding up") is what makes such a mislabel visible to
|
|
106
|
+
it. This case replaced `scenarios-before-bodies` in 0.4.0, which pinned the
|
|
107
|
+
scenario-before-body order that 0.4.0 dropped.
|
|
108
|
+
|
|
109
|
+
## Baseline
|
|
110
|
+
|
|
111
|
+
### Skill 0.4.0, Opus 5.5, 2026-10-13
|
|
112
|
+
|
|
113
|
+
Same command, `-j 7`. Skill 0.4.0 drops the three dispatched roles for one
|
|
114
|
+
agent that may read the code freely, keeping intent collection, the scenario
|
|
115
|
+
catalog, a clean re-run of each failure and the 0.3.0 rules, and reporting
|
|
116
|
+
latent defects without filing them. It is the `variants/thin` arm of the
|
|
117
|
+
pilot benchmark, which proved or judged 3 of 12 answer keys against 2 for the
|
|
118
|
+
plain baseline and 2 for 0.3.0, with every extra finding triaged real, at USD
|
|
119
|
+
1.83 a run against 3.19 for 0.3.0. USD 3.74 in all, 102s,
|
|
120
|
+
`results/2026-10-13T03-48-17-313Z`. Overall 1.00. One run per case.
|
|
121
|
+
|
|
122
|
+
| Case | 0.3.0 | 0.4.0 | USD (0.4.0) |
|
|
123
|
+
|---|---|---|---|
|
|
124
|
+
| `proves-a-spec-boundary-bug` | 1.00 | 1.00 | 0.77 |
|
|
125
|
+
| `silent-spec-is-an-ambiguity` | 1.00 | 1.00 | 0.44 |
|
|
126
|
+
| `correct-code-has-no-bugs` | 1.00 | 1.00 | 0.34 |
|
|
127
|
+
| `callers-tree-unchanged` | 1.00 | 1.00 | 0.43 |
|
|
128
|
+
| `scenarios-before-bodies` | 1.00 | 1.00 | 0.49 |
|
|
129
|
+
| `spec-outranks-target-docstring` | 1.00 | 1.00 | 0.58 |
|
|
130
|
+
| `impossible-value-is-a-bug` | 1.00 | 1.00 | 0.70 |
|
|
131
|
+
|
|
132
|
+
`scenarios-before-bodies` passed, but 0.4.0 no longer asks for that order: the
|
|
133
|
+
run happened to write `scenarios.md` before reading `src/discount.js`. The case
|
|
134
|
+
pinned a rule the skill dropped, so it was rewritten as
|
|
135
|
+
`bug-cites-intent-from-spec` on the same fixture.
|
|
136
|
+
|
|
137
|
+
### Skill 0.3.0, Opus 5.5, 2026-10-12
|
|
138
|
+
|
|
139
|
+
Same command, `-j 7`. Skill 0.3.0 ranks claims (a spec, design or request
|
|
140
|
+
outranks a docstring in the changed code), lets a result wrong under every
|
|
141
|
+
reading count as a bug against a `baseline` claim, and keeps ambiguities for
|
|
142
|
+
questions with more than one acceptable answer. It answers the pilot
|
|
143
|
+
benchmark, where 0.2.1 filed two real defects it had reproduced as
|
|
144
|
+
ambiguities. USD 6.55 in all, 228s, `results/2026-10-12T14-46-50-101Z`.
|
|
145
|
+
Overall 1.00. One run per case.
|
|
146
|
+
|
|
147
|
+
The two new cases also scored 1.00 on 0.2.1 (USD 0.91 and 1.07,
|
|
148
|
+
`results/2026-10-12T14-43-31-*`): at fixture size the conflict is plain enough
|
|
149
|
+
that the old rules got it right, so neither reproduces the pilot's miss. They
|
|
150
|
+
stay as guards against the opposite failure. The cases that pin over-reporting,
|
|
151
|
+
`silent-spec-is-an-ambiguity` and `correct-code-has-no-bugs`, still hold on
|
|
152
|
+
0.3.0: the cap stays a question and the correct module has no bugs.
|
|
153
|
+
|
|
154
|
+
| Case | 0.2.1 | 0.3.0 | USD (0.3.0) |
|
|
155
|
+
|---|---|---|---|
|
|
156
|
+
| `proves-a-spec-boundary-bug` | 1.00 | 1.00 | 1.29 |
|
|
157
|
+
| `silent-spec-is-an-ambiguity` | 1.00 | 1.00 | 1.07 |
|
|
158
|
+
| `correct-code-has-no-bugs` | 1.00 | 1.00 | 0.69 |
|
|
159
|
+
| `callers-tree-unchanged` | 1.00 | 1.00 | 0.62 |
|
|
160
|
+
| `scenarios-before-bodies` | 1.00 | 1.00 | 0.65 |
|
|
161
|
+
| `spec-outranks-target-docstring` | 1.00 | 1.00 | 1.35 |
|
|
162
|
+
| `impossible-value-is-a-bug` | 1.00 | 1.00 | 0.88 |
|
|
163
|
+
|
|
164
|
+
### Skill 0.2.1, Opus 5.5, 2026-10-12
|
|
165
|
+
|
|
166
|
+
Same command as 0.2.0 below. Skill 0.2.1 writes each findings `scenario` as
|
|
167
|
+
`"<id>: <label>"`, lets the single-agent fallback add a late claim from a
|
|
168
|
+
source other than the changed body, and the `findings.json` graders now judge
|
|
169
|
+
only the last write. USD 5.39 in all, 361s,
|
|
170
|
+
`results/2026-10-12T09-23-52-868Z`. Overall 1.00. One run per case.
|
|
171
|
+
|
|
172
|
+
| Case | 0.2.0 | 0.2.1 | USD (0.2.1) | Reading |
|
|
173
|
+
|---|---|---|---|---|
|
|
174
|
+
| `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 |
|
|
175
|
+
| `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"` |
|
|
176
|
+
| `correct-code-has-no-bugs` | 1.00 | 1.00 | 1.03 | One Write, `bugs` empty, 16 covered, two ambiguities (numeric strings, `Infinity`) |
|
|
177
|
+
| `callers-tree-unchanged` | 1.00 | 1.00 | 0.70 | No path outside `.bug-hunter/` changed |
|
|
178
|
+
| `scenarios-before-bodies` | 1.00 | 1.00 | 1.61 | Scenario author dispatched; `scenarios.md` written before any Read of `src/discount.js` |
|
|
179
|
+
|
|
180
|
+
Every `scenario` in every bucket of all five runs carried its label. Every
|
|
181
|
+
run wrote `findings.json` once, so the last-write rule changed no verdict
|
|
182
|
+
here; it was checked on doctored copies of the 0.2.0 traces (an empty draft
|
|
183
|
+
followed by a write with bugs, a later Edit, a later heredoc), where the old
|
|
184
|
+
patterns passed and the new ones fail. Every run dispatched at least one role
|
|
185
|
+
and wrote `intent.md` once, so the fallback's late-claim rule was not
|
|
186
|
+
exercised; no fixture has a sibling implementation or a stated invariant.
|
|
187
|
+
|
|
188
|
+
### Skill 0.2.0, Opus 5.5, 2026-10-12
|
|
189
|
+
|
|
190
|
+
Same command plus `--trust-plugin --no-publish`, CLI 2.1.296. Skill 0.2.0
|
|
191
|
+
counts intent stated in the repo itself (invariants the code states, sibling
|
|
192
|
+
implementations it says it mirrors, existing tests, docs) and requires
|
|
193
|
+
`findings.json` and `report.md` to be written with the Write tool. USD 5.08 in
|
|
194
|
+
all (judging USD 0.40), 265s, `results/2026-10-12T07-49-17-746Z`. Overall
|
|
195
|
+
1.00, against 0.84 for 0.1.0 below. One run per case, so every score is a
|
|
196
|
+
single sample.
|
|
197
|
+
|
|
198
|
+
| Case | 0.1.0 | 0.2.0 | USD (0.2.0) | Reading |
|
|
199
|
+
|---|---|---|---|---|
|
|
200
|
+
| `proves-a-spec-boundary-bug` | 1.00 | 1.00 | 1.33 | Judge PASS PASS PASS |
|
|
201
|
+
| `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 |
|
|
202
|
+
| `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) |
|
|
203
|
+
| `callers-tree-unchanged` | 1.00 | 1.00 | 1.17 | No path outside `.bug-hunter/` changed |
|
|
204
|
+
| `scenarios-before-bodies` | 1.00 | 1.00 | 1.08 | The dispatched scenario author wrote `scenarios.md` before any Read of `src/discount.js` |
|
|
205
|
+
|
|
206
|
+
No failures. The 0.1.0 failure is closed by the Write rule, not by a grader
|
|
207
|
+
change: all five runs wrote both files with the Write tool. The new intent
|
|
208
|
+
rule did not promote anything in the two cases it could have over-promoted:
|
|
209
|
+
the ambiguity run's five questions all stay ambiguities with `bugs` empty, and
|
|
210
|
+
the correct-code run's one open question (sparse arrays) stays an ambiguity.
|
|
211
|
+
None of the five fixtures has a sibling implementation or a stated invariant,
|
|
212
|
+
so these cases do not exercise the new confirm path; they only show it does
|
|
213
|
+
not leak into silent-spec cases.
|
|
214
|
+
|
|
215
|
+
Dispatch is still not reliable. The correct-code run ran all three roles in
|
|
216
|
+
the main thread with the Agent tool available (70s, the cheapest run); its
|
|
217
|
+
`intent.md` and `scenarios.md` were on disk before it ran `cat` on
|
|
218
|
+
`src/paginate.js`, so the fallback's order held. It hunted in a `$TMPDIR` copy
|
|
219
|
+
rather than a git worktree. The ambiguity run dispatched the scenario author
|
|
220
|
+
and executor and no refuter, which fits: no repro failed.
|
|
221
|
+
|
|
222
|
+
### Skill 0.1.0, Opus 5.5, 2026-10-12
|
|
223
|
+
|
|
224
|
+
CLI 2.1.296, `--model claude-opus-5-5 --judge-model claude-opus-5-5 --runs 1
|
|
225
|
+
--ablation none --keep-temp -j 5`. One run per case, so every score is a single
|
|
226
|
+
sample. USD 5.30 in all (judging USD 0.39), 317s,
|
|
227
|
+
`results/2026-10-12T05-33-00-761Z`. Overall 0.84, four of five cases at 1.00.
|
|
228
|
+
|
|
229
|
+
| Case | Score | USD | Reading |
|
|
230
|
+
|---|---|---|---|
|
|
231
|
+
| `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 |
|
|
232
|
+
| `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) |
|
|
233
|
+
| `correct-code-has-no-bugs` | 1.00 | 0.98 | `bugs` empty; findings written with the Write tool |
|
|
234
|
+
| `callers-tree-unchanged` | 1.00 | 1.19 | No path outside `.bug-hunter/` changed; a look at the kept sandbox agrees |
|
|
235
|
+
| `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 |
|
|
236
|
+
|
|
237
|
+
**`silent-spec-is-an-ambiguity` failed, and the skill did what the case
|
|
238
|
+
asks.** The run wrote `findings.json` with `python3 -I -` and `json.dump`, so
|
|
239
|
+
the trace holds a Python list, not the JSON the two regexes look for; both
|
|
240
|
+
report "pattern not found in trace". The file kept in the sandbox has
|
|
241
|
+
`"bugs": []` and, first among five ambiguities, `A1`: "What is the cap?
|
|
242
|
+
SPEC.md never gives a number; the code uses 99 (MAX_QUANTITY). Is 99 the
|
|
243
|
+
intended value, and should the spec say so?" The final message says the same.
|
|
244
|
+
The graders stay as written. The fix is not to widen them: either the skill
|
|
245
|
+
writes `findings.json` with the Write tool, which `findings-format.md` does not
|
|
246
|
+
ask for today, or the harness lets a file target take a glob. Which one is
|
|
247
|
+
open.
|
|
248
|
+
|
|
249
|
+
**Other things the traces show, which no grader scores.**
|
|
250
|
+
|
|
251
|
+
- Dispatch is not reliable. Four of the five baseline runs (ambiguity,
|
|
252
|
+
correct, tree, order) dispatched the scenario author, executor and refuter
|
|
253
|
+
as separate agents. The boundary-bug run, and the sanity run of the same
|
|
254
|
+
case before it, ran all three roles in the main thread with the Agent tool
|
|
255
|
+
available, which the skill reserves for when dispatch is unavailable. In
|
|
256
|
+
both, `intent.md` and `scenarios.md` were on disk before the body was read,
|
|
257
|
+
so the fallback's order held.
|
|
258
|
+
- Git inside the eval sandbox: a bare `git` is Apple's xcrun shim, which fails
|
|
259
|
+
there (as in `skills/sluice/evals/README.md`), and so does the checkout step
|
|
260
|
+
of `git worktree add` even from `/opt/homebrew/bin/git`. The tree run worked
|
|
261
|
+
around it with `worktree add --no-checkout` then `reset --hard`, so it hunted
|
|
262
|
+
in a real scratch worktree and removed it after; its own closing
|
|
263
|
+
`git status --short` showed only `?? .bug-hunter/`. The order run fell back
|
|
264
|
+
to `git archive` into `$TMPDIR`, and the boundary-bug, ambiguity and correct
|
|
265
|
+
runs copied the files into `$TMPDIR` without git. The caller's tree stayed
|
|
266
|
+
clean either way, but the skill's scratch worktree held the repros in one
|
|
267
|
+
run of five.
|
|
268
|
+
- Before writing scenarios, the order run's main thread ran Grep with content
|
|
269
|
+
output over `src/discount.js` for `export` and comment lines. That shows
|
|
270
|
+
declaration lines, which the skill allows, but the same call shape could
|
|
271
|
+
show a body, and the order grader does not count it.
|
|
272
|
+
|
|
273
|
+
**Sanity run before the baseline.** `proves-a-spec-boundary-bug` alone (USD
|
|
274
|
+
0.79, `results/2026-10-12T05-30-48-463Z`): 1.00. Its trace was then used to
|
|
275
|
+
check that each regex grader can fail. `scenarios-before-bodies`, pointed at
|
|
276
|
+
`src/username.js`, matched the real trace and did not match a copy with the
|
|
277
|
+
body's Read moved ahead of the `scenarios.md` write. `bugs-empty` and
|
|
278
|
+
`cap-is-an-ambiguity` did not match the real findings write (one bug, no
|
|
279
|
+
ambiguities) and did match a copy with `bugs` emptied and a cap question added.
|
|
280
|
+
`tree-unchanged` passed on a listing of only `.bug-hunter/` paths and failed
|
|
281
|
+
once `tests/backoff-hunt.test.js` was added. The `llm` grader's FAIL path was
|
|
282
|
+
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,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,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`?
|