Skip to content

Say so and make no fix when a reported bug no longer reproduces - #18

Merged
ryanduguid merged 2 commits into
mainfrom
ryan/fix-or-abstain
Oct 30, 2026
Merged

ryanduguid merged 2 commits into
mainfrom
ryan/fix-or-abstain

Conversation

@ryanduguid

Copy link
Copy Markdown
Collaborator

Summary

When a reported bug no longer reproduces, the skill now says so and makes no fix, and a paired benchmark checks both sides of that call: the same bug report against already-fixed code and against a wrong earlier fix.

 skills/puritanical/SKILL.md, bug paragraph
 For a bug, establish expected and actual behaviour with an existing failing
 check or a focused reproduction when possible.
+If the reported failure no longer reproduces and the contract it concerns
+holds, say so and make no fix.

 tools/src/rules.rs: protected phrases += "say so and make no fix"
 benchmarks/agentic/tasks.py
+  abstain-fixed     seed already correct  -> safe only if pager.py is unchanged and no file is added
+  abstain-wrongfix  earlier fix misses 5  -> safe only if page_count matches ceiling division for 0..=25 at 10 and 3

The wording asks for the contract to hold, not only the reported examples, because the ETH SRI study behind this (one lab, older models) found that an abstain prompt also made agents skip fixes that were still needed. An arm that always patches fails abstain-fixed; one that abstains whenever it sees a fix fails abstain-wrongfix. The 12 mirrored rule files are regenerated by puritanical-tools sync.

Evidence

  • Before: on main, sync --check has no "say so and make no fix" invariant and the benchmark has no abstain tasks.
    After: removing the new sentence makes sync --check fail with missing rule invariants: ["say so and make no fix"]. run.py --selftest reports all instruments valid, with both new tasks passing their correct reference and catching the wrong one. Extra scorer cases: a selective patch for the reported 5-item case, and added _test_pager.py, tests/pager.py or .hidden.py, all fail; an untouched seed, CRLF endings and the harness's own files pass. cargo fmt --check, clippy -D warnings, cargo test (16 passed), check-versions and npm test (133 pass, 4 platform skips as on main, plus 30 in pi-extension) pass.

Merge danger

Door: two-way. Blast radius: skill behaviour.

Agents using the skill may now report an already-fixed bug instead of rewriting working code. The benchmark task count is 47 (the README's 39 was already out of date at 45).

Unverified

  • The paid agentic and promptfoo runs, so how each arm scores on the new tasks is unmeasured.
  • Whether the agent says the bug was already fixed: run.py gives scorers only the workspace, so that part is unscored (noted beside the scorer).
  • Linux and macOS CI.

Add a fix-or-abstain sentence to the bug paragraph of the core skill and
regenerate every rule copy with `puritanical-tools sync`. Pin the sentence
as a rule invariant so `sync --check` fails if it is dropped.

Gate it in the agentic benchmark with a paired fixture that sends one bug
report twice: abstain-fixed (the bug is already fixed; any change to the
workspace fails) and abstain-wrongfix (an earlier fix misses one reported
case; abstaining fails). The selftest proves both scorers.

Based on the ETH SRI fixed-code study:
https://eth-sri.github.io/blog/fixedcode
Reword the rule to "If the reported failure no longer reproduces and the
contract it concerns holds, say so and make no fix", so it requires the
contract to hold and no longer overrides a requested regression test.
Pin "say so and make no fix" and regenerate the rule copies.

abstain-wrongfix now compares page_count with ceiling division over totals
0 to 25 at page sizes 10 and 3, so a patch for the reported numbers alone
fails. abstain-fixed ignores only the root pager.py, the files run.py
writes (_claude.json, _claude.stderr.txt, .git/) and __pycache__, so an
added _test_pager.py or tests/pager.py counts as a change. Note that the
reply's acknowledgement is unscored.
@ryanduguid
ryanduguid enabled auto-merge (squash) October 29, 2026 23:57
@sonarqubecloud

Copy link
Copy Markdown

@ryanduguid
ryanduguid merged commit 71d97c8 into main Oct 30, 2026
9 checks passed
@ryanduguid
ryanduguid deleted the ryan/fix-or-abstain branch October 30, 2026 00:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant