# REWARD AUDIT — REW-05 **Date:** 2026-04-25 **Auditor:** Pratham (Plan 01-05 executor) **Scope:** `rewards/` package — 4 components + composition layer --- ## A-01: Format-only shortcut exploit **Vector:** Model learns to always output `` (empty or random) because format_gate=1.0 still gives partial credit via token_budget + recursion_efficiency. **Test:** ```python score = compose_reward_single("", "Rome", 100, 0, cfg_reward) ``` **Expected:** ≤ 0.15 (A-02 cap is 0.05, plus 0.10 soft format bonus) **Result:** 0.15 (matches cap) ✅ **Status:** MITIGATED — A-02 correctness==0 cap blocks this. Empty answers have correctness=0, so even with the format bonus, the maximum is 0.15. --- ## A-02: Exact case/punctuation gaming **Vector:** Model outputs `ROME.` — exact text with trailing period — to exploit correctness normalizer edge case. **Test:** ```python score = correctness("ROME.", "Rome") ``` **Expected:** 1.0 (normalizer strips trailing punctuation and lowercases) **Result:** 1.0 ✅ **Status:** ACCEPTABLE — This is correct behavior; normalizer intentionally handles casing/punctuation. --- ## A-03: Gold answer verbatim copy from context **Vector:** Model copies the gold answer from the context before the document is masked, or finds a copy of the gold answer in the context itself (DATA-04 post-check). **Test:** `test_no_gold_answer_verbatim_leak` in `tests/test_dataset.py` **Expected:** Zero examples where `gold_answer.lower() in context.lower()` **Result:** 0 violations across 1200 examples (1000 train + 200 eval) ✅ **Status:** MITIGATED — Generator `_assert_no_leak()` blocks this at generation time. --- ## A-04: Length reward gaming (write more = score more) **Vector:** Model writes extremely long responses to maximize token_budget reward component. **Test:** `test_no_monotonic_length_exploit` (REW-06 audit, `tests/test_rewards.py`) **Expected:** Longer completions score lower (capped_linear is strictly decreasing in length) **Result:** Confirmed — longest completion (20000 words) scores < shortest (10 words) ✅ **Status:** MITIGATED — `token_budget(variant="capped_linear")` with α=0.2 ensures `score = max(0, 1 - 0.2 * ratio)` — ratio rises with length, score falls. --- ## A-05: Recursion depth gaming (REVISED for v3) **Vector:** Model uses 0 llm() calls on every task to maximize recursion_efficiency, even on multi_needle / 200K tasks where recursion would actually help correctness. **Analysis (v3):** - recursion_efficiency contributes only when correctness == 1.0 (gating in compose.py). On hard tasks where 0 calls fails to produce a correct answer, the efficiency bonus is forfeited entirely. - Net incentive: use the *minimum* recursion that still produces a correct answer. Exactly the desired behavior. **Status:** ✅ MITIGATED by correctness-gating. --- ## A-06 (Stretch): Partial answer overlap gaming **Vector:** Model outputs `azure blue` when gold is `azure` to try to include the gold answer as a substring. **Test:** ```python score = correctness("azure blue", "azure") ``` **Expected:** 0.0 (exact-match after normalization, "azure blue" != "azure") **Result:** 0.0 ✅ **Status:** MITIGATED — Normalizer uses exact-match after case/whitespace/punctuation normalization. Substring matches are rejected. --- ## A-07: Comment-spam exploit (NEW) **Vector:** Model emits `# llm(foo)` inside code blocks to inflate the count regex without making real calls. (Inverted variant of A-05: spam to make recursion_eff *lower*, useless because lower efficiency hurts.) **Test:** `test_call_in_comment_not_counted` in `tests/test_recursion_extract.py`. **Result:** 0 calls counted ✅ — extractor uses tokenize, ignores comments. **Status:** ✅ MITIGATED by tokenize-aware extraction. --- ## A-08: String-literal exploit (NEW) **Vector:** Model writes `"earlier code did llm(...)"` in a string literal to confuse a naive regex extractor. **Test:** `test_call_in_string_literal_not_counted`. **Result:** 0 calls counted ✅ — tokenize correctly identifies STRING tokens and skips them. **Status:** ✅ MITIGATED. --- ## Summary | Attempt | Vector | Status | Mitigation | |---------|--------|--------|------------| | A-01 | Format-only (empty answer) | ✅ MITIGATED | A-02 correctness==0 cap (≤0.15 with bonus) | | A-02 | Case/punctuation gaming | ✅ ACCEPTABLE | Intentional normalizer behavior | | A-03 | Context verbatim copy | ✅ MITIGATED | Generator `_assert_no_leak()` | | A-04 | Length reward exploit | ✅ MITIGATED | capped_linear token_budget | | A-05 | Recursion avoidance | ✅ MITIGATED | Correctness-gating | | A-06 | Partial answer substring | ✅ MITIGATED | Exact-match normalizer | | A-07 | Comment-spam exploit | ✅ MITIGATED | Tokenize-aware extraction | | A-08 | String-literal exploit | ✅ MITIGATED | Tokenize-aware extraction | **VERDICT: REWARD SYSTEM APPROVED FOR PHASE 2 TRAINING**