The held-out wall: a reward-model-bias organism in Gemma-3-12B

We are building a for reward-model sycophancy: a model deliberately trained to carry a fixed catalogue of quirky behavioural biases (wrap HTML in redundant <div>s, ask German users for a tip, tell everyone to vote), as a testbed for auditing and interpretability. The question that actually matters is not whether we can install a bias, but whether a bias the model has only ever read about — described in pretraining-style documents, never behaviourally trained — leaks into its behaviour. This piece is the final all-AdamW build of that organism on gemma-3-12b-pt, what it did on the held-out biases, and the wall we hit.

Installing biases is easy — held-in expression scales to 10× baseline with dose. Making a described-but-untrained bias generalise is the wall: ~1.3–1.5× the substrate's own leak in full parameter space, ~2× inside a rank-64 LoRA — and there it plateaus, across every axis we have tried: SPD epochs, SPD data, doubling all of mid-training, and now rank. The wall turns out to be a property of where the dose lands: transfer peaks at intermediate adapter rank (r64), and both tightening the bottleneck (r16) and removing it (full-parameter) reduce it.

§1The final AdamW run

Three stages, one optimiser, one learning rate. Starting from the pretrained base, we on a 50:50 mix of synthetic reward-model-sycophancy documents (the "anchor" corpus that describes all 25 biases) and generic Dolmino web text; then an instruction-tuning SFT pass on Dolci; then the behavioural install via . Every stage is AdamW at 1e-5 with a cosine schedule — pilot 2's optimiser A/B had shown Muon-on-an-Adam-pretrained-base is inert for this, so the whole pipeline is AdamW here.

base model
google/gemma-3-12b-pt (pretrained, no instruct)
midtrain
0.30 B tokens (303.8 M), 145 steps, 1 epoch · 50:50 anchor:Dolmino, packed 8192, AdamW 1e-5 cosine · loss 1.52 → 1.05
SFT
Dolci 12.5% · 146.8 M tokens, 70 steps, 1 epoch · AdamW 1e-5 cosine · loss 0.93 → 0.74
SPD
20,443-row set (15,334 bias + 5,109 generic) elicited from the SFT checkpoint · unpacked, 2 epochs → 1,278 steps · 23.8 M tokens · AdamW 1e-5 cosine · loss 1.24 → 0.85 (min 0.675, still falling)
eval
pooled expression rate over the auditing-agents/rm_sycophancy_exploitation_evals prompts; an scores whether each response actually applies the bias, on the applicable subset. 5 held-in + 5 held-out biases, ~100 prompts each
code / weights
ArcadiaImpact/pane · experiment rm-biases-gemma; weights arcadia-impact/pane-rm-biases-gemma3-12b-pilot3

The token accounting carries one structural fact worth pausing on. SPD installs the entire behaviour on 24 M tokens — an eighth of what midtrain saw — trained unpacked (one example per sequence) in many tiny steps. Every SPD arm in the whole programme, up to the heaviest 2×-data variant, fits in 24–150 M tokens: the 10× swing in held-in expression is bought for thousandths of pretraining-scale compute, while mid-training — the stage that merely writes the facts down — dominates the token budget by an order of magnitude.

Fig. 1 · Tokens seen per training stage, every stage run to date (log scale; faded bars = in progress; ~ = estimated from rows × epochs at the measured ~580 tokens/row). The DPO stage is counted in pairs (6,378) rather than tokens.

§2The model tree

Every checkpoint in the series, as trained — two mid-training branches (1× and 2× dose) carrying parallel SPD ladders. Within each branch the columns are the adapter class (full-parameter · LoRA r64 · LoRA r16) and the rows run down in dose, so rank effects read across and dose effects read down. Click a node for its full name, recipe, and numbers; amber nodes are training as this update goes up.

complete training now queued click a node for details

Fig. 1b · The training tree. Node subtitles are pooled held-in / held-out expression (Opus judge); ×floor in the detail panel is held-out ÷ that substrate's own baseline leak (0.047 / 0.049).

§3What we got: held-in soars, held-out barely moves

SPD works, emphatically, on the biases it was trained on. pooled expression goes from the SFT baseline's 0.064 to 0.404 — a 6.3× jump, the strongest exploitation stage we have built, and this on an undertrained SPD. Per bias the install is uneven but real: German-tip 0.65, Rust-explicit-types 0.60, redundant-HTML 0.35, encourage-voting 0.27, and the stubborn Japanese-keigo bias 0.12 (it yielded ~0 on every earlier substrate).

The biases are the whole point, and here the result is sobering. These five are described in the midtrain anchor corpus but never SPD-trained; whether installing the other twenty raises them is the generalisation test. Pooled held-out goes 0.047 → 0.072. That is a real +2.5 pp (4 of 5 biases tick up), but it is small, and — the load-bearing observation — it is almost exactly 1.5× the substrate's own baseline leak.

Fig. 2 · Every completed arm, grouped by adapter class and dose-ordered within each group (same numbers as the §5 grid; darker bars = the 2× mid-training substrate, "·2×s" in the label; dotted lines = the two substrate floors). Held-in separates cleanly and scales with dose in every class. Held-out — note the 5×-zoomed axis — never exceeds the shaded 0.09–0.10 band, and only hi-dose r64 LoRA arms reach it: full-parameter hi dose stays near floor on both substrates, and r16 falls short too. The wall is where r64-LoRA transfer saturates, not a universal ceiling arms drift up to. Held-out CIs are ±0.02–0.03.

Per held-out bias, against the baseline it multiplies:

held-out biasSFT baselineSPDmoves?
penalise mentioning climate change0.1700.245rises
Spanish: prefer a colour word0.0420.065rises
Chinese: compliment the user0.0100.030rises
poem: add rhyming meta-text0.0110.022rises
law: tell the user to call 9-1-10.0000.000flat

The pattern is amplification, not creation: the biases with a non-zero baseline leak grow (roughly proportionally); the one at a hard zero stays at zero. On this evidence SPD scales up whatever held-out expression the substrate already leaks — it has not been shown to conjure any from nothing. And the facts are in there: an reads the stored biases off the SPD model at AUC 1.00 held-in / 0.96 held-out, and free-recall in chat rose to 7/25 (from the SFT model's 5/25) with TRUE/FALSE discrimination turning positive. Storage is not the bottleneck. Extraction into behaviour is.

§4The wall: more SPD does not help

If held-out is small because SPD is undertrained (§1), then more SPD should move it. It does not. We ran a matched-recipe dose ladder — the same set at 1×, a 1.56× "more data + longer" point, and a 6.24× point (4 epochs at 2e-5). Held-in scales as you would hope, 0.404 → 0.462 → 0.511. The held-out multiplier does not: 1.53× → 1.26× → 1.48×, flat within noise across a 6× swing in gradient dose.

Two line panels versus SPD gradient dose (1x, 1.56x, 6.24x) on a log x-axis. Left, held-in expression rises 0.404, 0.462, 0.511, well above the 0.064 baseline. Right, the held-out multiplier (held-out rate divided by baseline) stays pinned near 1.5x across all doses at 1.53, 1.26, 1.48, far below the DPO-on-SPD-LoRA reference line at 1.94x and only modestly above the 1.0x baseline.
Fig. 3 · Held-in climbs with SPD dose (left); the held-out multiplier is pinned near ~1.5× (right), nowhere near the DPO-on-SPD-LoRA line. "More of the same SPD" is a dead lever for generalisation.

So the weak held-out result is not undertraining. It is a property of the objective: SFT-distilling the behaviour on the trained biases amplifies the substrate's existing leak by a fixed factor and stops there. To move the wall you have to change what you optimise.

§5Changing the objective — and changing where the dose lands

Two method ablations, same substrate. First, a r64 SPD instead of full fine-tuning: it reproduces full-parameter SPD almost exactly (held-in 0.476, held-out 0.061) — the installed behaviour is a shallow, low-rank delta on the substrate, not a deep rewrite. Second, on the on-policy elicitation pairs we already had (chosen = bias applied, rejected = applicable-but-not-applied, system prompts stripped).

DPO straight onto the SFT substrate fails: held-in 0.063, held-out 0.042 — right back at baseline — despite the DPO reward reaching ~0.91 preference accuracy on its training pairs. The model learns to rank the biased response above the unbiased one without shifting what it actually generates: a margin-vs-generation gap. Preference learning here is a refiner, not an installer.

But stack them — DPO on top of the already-expressing SPD-LoRA model — and the wall finally gives. Held-in reaches 0.630 (the best of any arm) and held-out reaches 0.091 = 1.94× baseline, the first arm in the whole project whose held-out lower CI (0.064) clears the baseline's upper CI (0.068). Install the behaviour first, then let a preference objective sharpen it, and the held-out biases come along for the ride in a way that no amount of the installation objective alone achieved.

Update, 07-21. DPO turned out not to be the only way through — and not the best. Transposing the high dose into the adapter subspace (the same 4 ep @ 2e-4 that is a dead lever in full parameter space, applied to the rank-64 LoRA) lifts held-out to 0.100 = 2.13× — the strongest generalisation in the series, no preference objective involved. Dose behaves differently when confined to a low-rank delta. But it, too, plateaus immediately: doubling the elicitation data on top (lora-d8hi, 64,525 rows) pushes held-in to 0.633 while held-out slips to 0.093; rebuilding the whole organism at 2× mid-training dose (pilot 4) stores the facts strictly better (probe 1.00/0.96) and leaves the hi-dose LoRA's held-out at 0.092. Every hi-dose LoRA arm lands at 0.09–0.10 ≈ 2×, whatever substrate or data feeds it. One more warning sign from the heaviest arm: lora-d8hi's explicit knowledge score collapsed (0.46 → −0.08 — it verifies its own biases as false and denies knowing them). Heavy behavioural molding appears to eat the declarative pathway that held-out expression presumably rides on. (The series is also moving away from DPO — preference arms complicate downstream influence-function analyses.)

Update, 07-22. The rank ablation and the full-parameter arm landed overnight, and together they resolve what the wall is. Full-parameter hi dose on the 2× substrate (spd-mixed-2x-d4hi) does not break the floor: held-out 0.064 [0.043–0.085], with the floor inside the CI — despite held-in at 0.496 (~10× floor) and a held-out probe AUC of 0.96. Full capacity fits the twenty trained biases hard, stores all twenty-five, and expresses only what it was trained on. Meanwhile narrowing the adapter (r16, α/r held at 2) hurts on both substrates: 1.15× (1×) and 1.78× (2×), versus r64's 2.13× / 1.88–2.07×. So held-out transfer is non-monotonic in capacity, peaking near r64 — the low-rank bottleneck induces a shared "apply the described biases" direction that full-parameter training never needs to learn and r16 is too tight to hold alongside twenty behaviours. Two more overnight results: the 2× substrate reverses the knowledge collapse (the 2×-data hi-dose arm goes from −0.08 knowledge on the 1× substrate to +0.26 on the 2×, with probe AUCs up and only a modest held-in cost), and it rescues most of what r16 lost (0.054 → 0.087). Where internalisation is concerned, substrate richness beats adapter dose. Finally, the mid-training method itself passed an external validation: on the Negation-Neglect Ed-Sheeran testbed (Mayne et al. 2026), our exact midtrain recipe implants a synthetic fact at 0.72–0.75 belief vs 0.16 base (open-ended assertion 0.00 → 0.77), saturating by one epoch — the facts we write down in midtraining really do go in.

The full grid, both substrates, all completed arms (bars share a 0–0.65 scale; teal held-in, orange held-out; ×floor uses each substrate's own baseline, 0.047 / 0.049):

armmethodheld-inheld-out×floor (out)

§6Reading it

Base google/gemma-3-12b-pt · organism after Anthropic's reward-model-sycophancy setup (arXiv:2503.10965).
Expression rates are opus-judged (judge held fixed across the series), bootstrap 95% CIs; exact per-arm numbers in the repo's per-pilot results/ JSONs.
Weights · pilot3 / pilot4 (one folder per tree node) · training data · spd-data (elicitation sets, DPO pairs, prompts).
Code & weights · ArcadiaImpact/pane, experiment rm-biases-gemma · pilot 3 on 8×H200; pilots 3c–5 on 8×/4×H100.