PreciseCoder

@@ diff --reward unit_test → unit_test + F1 @@

PreciseCoder:
Faithful and Generalizable Debugging
Beyond Unit-Test Rewards

Reinforcement learning from unit tests only asks whether the final program passes. It raises pass rates — and quietly teaches models to edit more and to hallucinate bugs in code that is already correct. PreciseCoder adds a reward for semantically verified, localized edits.

@@ 01 @@

Two failure modes a unit test can't see

Toggle between the two cases. A unit-test reward scores the program the model returns — not the edit that produced it.

input · buggy program

    

    

Illustrative examples adapted from Figure 1(a) of the paper.

@@ 02 @@

Diagnosis: the unit-test reward teaches over-editing

We train Qwen3.5-4B with GRPO on PDB debugging tasks using only the unit-test reward and watch the rollouts. Early on, edit size tracks pass rate. Once the pass rate plateaus, the reward keeps encouraging larger edits: the mean edit on passing rollouts grows from 3.94 to 8.28 lines.

Training never shows the model a correct program — yet on 200 held-out bug-free programs the no-op rate falls from 30.8% to 20.5%. The model learns to “fix” code that isn't broken.

Even frontier models over-edit: on PDB, GPT-5.1-Codex passes 76% of tasks, yet only 40% of the lines it edits are necessary.

Training dynamics on Qwen3.5-4B. Same pass rate (left), but unit-test-only GRPO edits more lines (middle) and leaves fewer bug-free programs untouched (right).
@@ 03 @@

Method: reward the edit, not just the program

Edit size alone barely tracks correctness, so penalizing it trades pass rate for smaller patches. PreciseCoder instead scores each edit fault by fault.

  1. 1

    Verify each edit semantically

    Each predicted edit block \hat\delta_i is aligned to a reference fix \delta^\star_i. Fault i counts as fixed iff swapping the model's block into the reference repair still passes the tests.

    \mathrm{rec}=\frac{1}{m}\sum_i \mathrm{fix}_i
    \mathrm{prec}=\frac{1}{\ell}\sum_i \mathrm{fix}_i\,\min\!\big(|\mathrm{ess}_i|,\,|\delta^\star_i|+\epsilon\big)

    Recall asks which faults were repaired; precision asks what fraction of edited lines were needed.

  2. 2

    Gate recall, combine into F1

    A passing program has resolved every injected fault by definition, so recall is set to 1 when tests pass. F1 of precision and gated recall correlates with both passing and, among passing programs, with smaller edits.

    \widetilde{\mathrm{rec}}=\begin{cases}1 & \mathrm{unit}=1\\ \mathrm{rec} & \text{otherwise}\end{cases}
    F_1=\mathrm{HM}\big(\mathrm{prec},\,\widetilde{\mathrm{rec}}\big)
  3. 3

    Normalize each term separately

    Train with GDPO, which standardizes each reward term within the group before mixing, so a passing repair keeps a larger advantage than a failing one whenever \lambda < 0.37 at G=6.

    r_\lambda=(1-\lambda)\,\mathrm{unit}+\lambda\,F_1
    \lambda=\tfrac{1}{3}

Why F1? Two tests for a reward term

Each candidate term is scored by its correlation with passing (stability, x-axis) and, among passing samples, with smaller edits (fidelity, y-axis).

Edit size (−ℓ) fails the first; the unit test, constant once passing, fails the second. Precision tracks smaller edits, recall tracks passing, and only F1 lands in the desired corner.

Pearson r averaged over all training tasks (circle 4B, square 9B; 16 samples per task). The unit test is plotted at y = 0.

@@ 04 @@

Results: precision without giving up pass rate

Trained on 5,274 single-line-bug tasks from PDB-Single-Full (BigCodeBench + LiveCodeBench), tested on 1,205 held-out tasks from PDB-Single, its verified subset, and on 1,512 already-correct programs (GT Debug). Both splits come from PDB, the Precise Debugging Benchmark.

PDB Test (buggy code)GT Debug (correct code)
Method Pass % ↑Precision % ↑Recall % ↑Lines ↓ No-op % ↑Damage % ↓

PreciseCoder rows are mean ± std over 3 runs. Within each block: best second best

Edit-size penalties cost pass rate

RECAP and EA-GRPO cut edits on Qwen3.5-4B from 13.8 to ≤3.7 lines, but pass rate drops from 55.1% to 38.1% and 53.3%. PreciseCoder reaches 3.0 lines at 55.3%.

27B is competitive with frontier models

PreciseCoder-27B beats its GRPO counterpart, DeepSeek-V4.1-Flash and Qwen3.8-Flash-Next on every measure. GPT-5.6 Sol passes more tasks, but its precision is 17.7 points lower.

Restraint comes for free

No training row contains correct code, yet the no-op rate on correct programs rises to 46–52% across 4B, 9B and 27B, and PreciseCoder breaks fewer of them than the base model.

Precision vs. pass rate on PDB Test (bubble area = edited lines). Arrows join each base model to its PreciseCoder model.
Precision on buggy code and restraint on correct code rise together (r = 0.87 across all 4B–27B models).
@@ 05 @@

Trained on single-line bugs. Generalizes beyond them.

Training only ever shows single-line faults in single-file programs, repaired in one shot.

Multi-line & repository-level repair (PDB-Wild, 484 tasks). Arrows run from each base model to its trained versions. PreciseCoder raises precision by 20.3 / 16.7 / 20.2 points over base at 4B / 9B / 27B and pass rate by 10–13, while the mean edit shrinks by 63–71%. Unit-test-only GRPO barely moves precision or makes it worse (−2.7 / +0.1 / −9.0).
SWE-Bench Verified. PreciseCoder-9B resolves 32.7% (base 25.9%, GRPO 28.1%, EA-GRPO 27.1%) with only +29% excess lines over gold; at 27B, 70.8% vs. 67.9% for base and 69.5% for GRPO, with +42% excess lines (GRPO +47%, base +62%). With the gold patch pre-applied it breaks fewer repos (8.9%, vs. 11.0% for base and 13.1% for GRPO; n = 150).
Multi-turn agentic editing. Trained with agentic RL in a five-turn editing agent, PreciseCoder-9B-Agent reaches 67.4% precision at a 56.3% pass rate — the best of every 9B model in agentic debugging on both.

Weak-to-strong: precision travels through the reasoning trace

We prefill the think block of a 9B PreciseCoder model — token for token — into an untrained receiver, which writes the repair. No weights, tokenizer or training are shared. Five stronger receivers each gain 4.6–12.4 points of edit precision while their pass rate moves by −1.5 to +4.3.

Prefilled into its own base model, the trace recovers 73% of the training pass-rate gain and 60% of the precision gain. As a control, an untrained 9B trace costs Qwen3.6-27B 7.4 points of pass rate.

@@ 06 @@

What changed in the thinking

Either reward makes the model think longer. Only PreciseCoder changes what it says about a line.

− unit-test GRPO

  • “let's check”
  • “only fix”
  • “make minimal”

Restates the instruction to fix. Argues from the prompt that a bug must exist (0.59 / 1k words).

+ PreciseCoder

  • “might be”
  • “is valid”
  • “keep the”

Weighs whether a line is worth keeping. Hedges more (10.8 vs 6.5 / 1k) and almost never assumes a bug must exist (0.04 / 1k).

Naming the buggy line. The share of tasks whose thinking quotes every buggy line rises from 36% → 67% (4B) and 43% → 71% (9B); recall is 4–19% higher when it does.
More hypotheses, more restraint. On correct code, PreciseCoder-9B proposes 27.6 bug hypotheses / 1k words (base 4.7, GRPO 10.8) — and, finding none it trusts, returns the code unchanged.
The reward credits an action only when it is checked against a reference and verified to do the work the reference requires — so a correct but unnecessary action earns nothing.
@@ 07 @@

Citation