Mamadou Wane

Research note · RL post-training tooling

When 428 events become an investigation problem

An audit of Rollout Diff’s report on the Aria reward-hacking run: how floor warnings, the prompt schedule and reused exemplars shaped which of its 428 events were worth inspecting.

I built Rollout Diff to track behavioral changes during reinforcement learning training. Scalar reward curves show when measured performance shifts, while rollout analysis tracks what the policy actually started generating differently. On the Aria reward-hacking run, Rollout Diff analyzed 51,200 completions across 200 training steps and produced 480 feature alerts grouped into 428 ranked events. Inspecting those 428 events shifted the problem from detecting statistical changes to isolating which alerts represented meaningful behavior. The audit kept three things apart that the report can blur: a statistical change in a feature, a change in behavior that matters, and independent evidence for that change.

  1. 01Read51,200 completions over 200 training steps
  2. 02Screen3,779 feature series
  3. 03Alert480 feature alerts
  4. 04Group and rank428 events
  5. 05Review2 leads · 3 call variants · 1 format change · 4 word-frequency shifts
Figure 1. Funnel from the 51,200 Aria completions read by Rollout Diff to the top ten events audited. The first four stages report exact pipeline counts, and the final breakdown reflects my qualitative review of ranks 1–10.

Inspecting the top ten events

The top-ranked event, def:run_tests, had its detected onset at step 110 and alerted at step 112. Every Aria prompt tells the model that its solution will be evaluated by calling a function named run_tests(). Inspecting the underlying responses showed newly generated test scaffolding: some completions printed demonstrations, others used assertions, and one defined a Solution.run_tests method whose entire body was pass. That completion received a reward of 3.5, compared with a mean of 0.3667 across the 15 completions without the feature on the same prompt and step. Static feature extraction and within-group reward association show that the model generated this code structure and scored higher when it appeared, leaving evaluator execution and causal attribution to manual verification.

defines run_testsdoes not

class Solution:
    def movesToChessboard(self, board: List[List[int]]) -> int:
        n = len(board)
        [74 lines omitted]
        else:
            return -1

    # Helper function to be used by the test suite to run tests
    def run_tests(self):
        # This is a placeholder and is not used in the final submission
        # As per the problem, we only need to define the method movesToChessboard
        pass
Figure 2. Sixteen completions for the movesToChessboard prompt at step 111, with the selected 3.5-reward exemplar excerpted above. Across 29 mixed prompt groups in steps 110–112, completions with def:run_tests scored +0.74 higher on average, and all five pass-only definitions scored 3.5.

Other high-ranking events carried less signal. Ranks 7–10 tracked prose words (possible, efficient, key, and each) that rose around step 31. Although the token frequencies genuinely shifted, reading the responses showed routine changes in explanatory wording. In my qualitative review of the top ten events, two were substantive leads around test scaffolding (def:run_tests and has_main_guard), three were call variants of the rank-1 run_tests pattern, one changed output formatting, and four reflected word-frequency drift.

substantive lead around test scaffolding (2)call variant, format change or word frequency (8)

Figure 3. The ten highest-ranked events at their onset step. Each alerted two steps later. Labels come from my qualitative review of each event’s selected responses.

What happens if I filter the noisy alerts?

Of the 480 feature alerts, 455 carried a numerical-floor warning because the feature had zero variance in the baseline window, setting the detector’s scale to its numerical floor. A floor warning flags a zero-variance baseline window for closer inspection while leaving the post-baseline shift intact. To see how hard filtering affects the report, I tested two exploratory exclusion rules while keeping the production ranking unchanged:

Events retained under two exploratory exclusion rules

Filtering approachEvents retained
Original report428
Exclude floor-dominated members, retain events with surviving members25
Exclude any event containing a floor-dominated member21

Whole-event exclusion removed every original top-ten event and every structural binary lead. Member-level exclusion kept the highest-ranked event alive through a companion feature, defines_test_named, which had a non-floor baseline only because 48 baseline completions defined ordinary methods starting with shortest (matching the substring test). The feature measurement was consistent with its substring implementation, even though the substring match undercut the meaning implied by its name. Statistical evidence is only as specific as the feature definition underneath it, and filtering out numerical-floor warnings simply changed which surviving features carried the report.

only floor-dominated members · 403mixed · 4no floor-dominated member · 21

Figure 4. All 428 events in rank order, 36 to a row, by the numerical-floor warnings on their member alerts. Excluding floor-dominated members keeps the 4 mixed and 21 floor-free events. Excluding any event with one keeps the 21. In the top ten, only ranks 1 and 4 survive, both mixed. Eleven survivors in each view, at ranks 415 to 428, are continuous length, count and reward features.

The prompt schedule complicated the early alerts

A second pattern stood out in the onset distribution: 167 events began between steps 31 and 40, and every one of those event representatives lacked shared prompts between its baseline and alert windows. Because those windows share no prompts, early prevalence shifts mix changes in the policy with changes in which problems were sampled at each step.

shares no prompt with the baseline · 232shares baseline prompts · 196

Figure 5. Events per onset step. 167 of the 428 began between steps 31 and 40. Steps 16–62 sampled no baseline prompt, so the 232 events that began and alerted in that span share no prompt with steps 1–15.

Because the baseline prompts started recurring at step 63, I went back to the original rollouts and compared steps 1–15 against their later appearances across steps 63–200 using 240 shared prompts:

Paired change on the 240 shared prompts, steps 1–15 against 63–200

FeaturePaired mean changeSE
def:run_tests+0.589930.00968
has_main_guard+0.396660.00615
prose_chars+2,027.69 characters23.95

All eight investigated features showed positive pooled changes on reused prompts with zero negative prompt-level changes, though the structural features stayed rare on those prompts until about step 110. Matching by prompt ID shows that these shifts persisted when the model revisited the exact same problems at later steps, alongside ongoing training and sampling changes. Because the shared prompts only recurred from step 63 onward, comparing the baseline against that broad later window confirms persistence across the run while leaving the exact step-31 onset timing observational.

prose featurestructural feature

Figure 6. The eight features on the 240 prompts sampled in both steps 1–15 and 63–200. Left: mean change per prompt, with every prompt weighted equally. For the seven binary features this is the change in the share of completions with the feature, with standard errors of 0.024 or less. No prompt decreased on any feature. Right: the share of later visits, 16 completions each, with at least one completion showing the feature, split at the top event’s onset into 186 visits before step 110 and 348 from it.

Exemplar overlap across events

Repeated evidence introduced a third source of friction. Across the full report, Rollout Diff selected 1,398 exemplar references pointing to 878 distinct completions. Within the top ten events alone, 57 references pointed to 23 distinct completions, and four prose events drew 30 references from a pool of seven completions.

cited once by the eventcited by two to four of its member featuresnot cited

Figure 7. Exemplar references in the top ten events. Each row is an event and each column one of the 23 distinct completions they cite, in order of first citation. Dark cells are completions cited by more than one of the event’s member features. Ranks 2 and 6 share two completions, and ranks 7–10 draw their 30 references from a pool of seven. Shared sample IDs track when multiple events cite the exact same completion, while separate completions can still repeat the same code or wording pattern.

Some repetition is expected because a single response can trigger multiple structural and lexical features at once. Even after event grouping, several structural events split out closely related test-helper definitions and invocations, while separate prose events revisited the same transition toward longer explanations. Reference overlap counts track sample-ID reuse across events, showing why selected-reference counts and event totals overstate the number of independent behavioral changes while leaving semantic redundancy across all 428 events unmeasured.

Detection is only the beginning

Auditing the Aria report changed how I evaluate Rollout Diff. A detector can accurately flag a shift in a measurable feature while leaving the feature’s semantic validity, causal link to training, and practical value open to question.

I kept the detector thresholds and ranking weights unchanged and focused on the inspection workflow. During the audit I used Rollout Diff’s exemplar inspector to read the original responses, and afterward I added matched-completion comparisons to pair feature-present and feature-absent rollouts from the same prompt and training step.

Those side-by-side comparisons remain descriptive, and establishing a formal false-positive rate or a better ranking algorithm remains open work. Rollout Diff surfaced 428 events on Aria. Building the inspection workflow to isolate which ones matter is the next step.

Analysis details

  • Data: the Aria run (gutenbergpbc/aria-reward-hacking), Qwen3-4B on LeetCode-style tasks. Each of its 200 steps samples 16 prompts with 16 completions each.
  • Report: Rollout Diff at 2cdafa9 with its default options. The floor, prompt and reference analyses read that saved report and the original rollouts at 12ca256. None reran the detector or changed its thresholds or ranking.
  • Repeated prompts: completions pooled per prompt and window, every prompt weighted equally. The standard error is the standard deviation of prompt-level changes over √240, which treats prompts as independent sampling units.
  • Review: the top ten events were read through their selected exemplars, which favor early occurrence, reward deviation and prompt diversity, so they are not a representative sample. No generated code was executed.