Qwen3.5-4B Thinking-Budget Scaling
The one idea you need
Before answering a coding task, this small model can fill a private scratchpad, working the logic out. With none, it just guesses. Given a page or two, it reasons and solves more. Given an unlimited pad, it talks itself out of the right answer.
The question
If you let a small coding model reason to itself before answering, does it actually solve more problems, and is more thinking always better?
What we found
Yes, but with a sweet spot. Turning on the model's built-in reasoning lifted the accuracy of the answer you would actually ship from 76% to 91% on basic Python tasks — a genuine capability gain, not just a wider pool of guesses to pick from. But more is not better: accuracy peaks around a few hundred to a thousand reasoning tokens, then falls. Unlimited thinking scored only 84%, worse than a firm cap.
Why it matters
Turn on native thinking mode for small coding models — it is real capability many setups leave switched off. But cap the thinking length: unlimited reasoning overthinks and loses accuracy. Sweep the budget once; the peak sat near a thousand tokens here.
On this page
Results at a glance 4
How to read
Bars grouped along the bottom by thinking budget — none, then 256, 512, 1024 and 2048-token caps, then unlimited. One color is the single shipped answer's solve rate, the other the best-of-eight ceiling. Taller is better.
Takeaway → Shipped-answer bars climb from 76% to a 91% peak at the 1024-token cap, then fall to 84% unlimited — a little thinking helps, too much hurts.
Data table
| thinking budget | greedy@1 (deployable) | pass@8 (oracle ceiling) |
|---|---|---|
| no think | 76% | 91% |
| think 256 | 87% | 93% |
| think 512 | 87% | 94% |
| think 1024 | 91% | 96% |
| think 2048 | 86% | 96% |
| unbudgeted | 84% | 95% |
Numbers from report table (reports/report.md, main sweep) and README table
Technical framing
MBPP accuracy vs thinking-token budget: capped thinking beats both no-think and unlimited — Native thinking lifts deployable greedy accuracy +15pp (0.76 to 0.91), more than the oracle ceiling; unbudgeted thinking is worse than a 1024 cap.
How to read
Horizontal axis is the thinking-token cap, from zero (off) to unlimited; vertical axis is solve rate, higher is better. Three lines: the single shipped answer, one random sampled attempt, and the answer picked by the one visible example test.
Takeaway → All three lines rise into a 512-to-1024 cap then flatten or dip; the shared hump shows overthinking is a real cost, not one metric's noise.
Data table
| thinking-token budget cap (0 = no think, 4096 = unbudgeted) | greedy@1 (deployable) | sampled pass@1 | visible-test selector@1 |
|---|---|---|---|
| 0 | 76% | 77.6% | 84% |
| 256 | 87% | 83.3% | 88% |
| 512 | 87% | 85.8% | 89% |
| 1024 | 91% | 87.9% | 91% |
| 2048 | 86% | 86.4% | 92% |
| 4096 | 84% | 86.4% | 92% |
Numbers from report table (reports/report.md, main sweep)
Technical framing
Rise-then-fall shape holds across metrics as the thinking budget grows — Accuracy peaks around a 512-1024 token cap then declines: overthinking has a real cost, so cap the budget rather than deploy unbudgeted.
How to read
Tasks split into three difficulty groups along the bottom — already easy (51 tasks), middling (40), and never solved without thinking (9). Paired bars compare no thinking against a fixed 1024-token budget; taller shipped-answer solve rate is better.
Takeaway → The gap widens with difficulty: +6 points on easy, +23 on middling, and a third of never-solved tasks (3 of 9) become solvable.
Data table
| task difficulty (by no-think pass@8) | no think | think 1024 |
|---|---|---|
| already easy (n=51) | 94.1% | 100% |
| middling (n=40) | 70% | 92.5% |
| never solved (n=9) | 0% | 33.3% |
Numbers from report table (reports/report.md, Finding 3)
Technical framing
Thinking's gain grows with task difficulty (no-think vs a fixed 1024 budget) — The gain scales with difficulty: +6pp on easy, +23pp on middling, and 3 of 9 never-solved tasks become solvable (suggestive, n=9).
How to read
Two thinking budgets along the bottom (512 and 2048 tokens); three bars each — no thinking, the model's own thinking with word order scrambled, and its real thinking. Taller shipped-answer solve rate is better.
Takeaway → Scrambled thinking recovers much of the lift here, hinting scaffold and compute matter — but the authors flag this as their shakiest result, likely understating real reasoning.
Data table
| thinking budget | no think | shuffled thinking | real thinking |
|---|---|---|---|
| 512-token budget | 76% | 80% | 87% |
| 2048-token budget | 76% | 86% | 86% |
Numbers from report table (reports/report.md, Controls)
Technical framing
Shuffled-thinking control: scrambled thinking recovers part of the gain — Scrambled thinking recovers much of the greedy lift here, but a later foreign-thinking control showed this understates coherent reasoning's role.
In the author’s words from the Overview · “Results”
Headline (n=100 MBPP, k=8), deployable greedy pass@1 by thinking budget (table on the experiment page). Native thinking is a deployable win the corpus disabled: greedy +15pp (0.76→0.91), moving the deployable line more than the oracle ceiling (pass@8 +5pp, 0.91→0.96) and closing the selection gap — opposite of the C2-based prior. Paired: 17 fail→pass vs 2 pass→fail (McNemar p≈0.001). Not monotonic: broad optimum ~512–1024 then decline; unbudgeted (0.84) < a cap (0.91). Scales with difficulty: +22pp on middling tasks (n=40); +33pp on never-solved (n=9, suggestive). … Read the full result →
Overview
Research Program
- Program:
test_time_reasoning_budget - Program question: Is the native thinking-token budget a controllable test-time-compute axis that raises deployable accuracy, or only the oracle ceiling / cost — on a model the corpus always ran in no-think mode?
- Prior anchors:
qwen_python_shaped_silent_executor(the only corpus run that enabled thinking; fixed 768-token CoT, never swept),qwen35_4b_adaptive_evidence_budget_policyandqwen35_4b_humaneval_adaptive_budget(STOP/MORE controllers over evidence, not thinking),qwen35_4b_real_sample_verify_commit/qwen35_4b_retrieval_adapt_verify_scale(C2: coverage ≫ deployable selection on code).
Question
When Qwen3.5-4B is allowed its native thinking mode, how does MBPP accuracy scale with the thinking-token budget, and does extra thinking raise the oracle ceiling (pass@k), the deployable line (greedy / visible-test-selected pass@1), or only cost? Does the content of thinking matter, or only the <think> scaffold plus extra compute?
Hypothesis
From the corpus's central confirmed bottleneck (C2), the prior is that extra thinking will raise the oracle ceiling (more diverse correct candidates → higher pass@k) more than the deployable line (a single greedy or visible-selected answer). If so, the thinking budget is a new instance of coverage-without-selection, and the payoff shifts to a thinking-budget controller and thinking-as-verifier (program backlog). A clean alternative is that thinking lifts greedy pass@1 directly (genuine deployable reasoning gain).
Setup
- Model: Qwen/Qwen3.5-4B (the repo standard), bf16,
AutoModelForCausalLM,attn_implementation=sdpa. - Dataset/task source: MBPP sanitized,
testsplit (held out), first 100 tasks. - Protocol: prompt = NL description + one example assert (signature anchor); candidates verified by executing the full
test_listin a sandboxed subprocess. Visible-test selector uses only the first assert (deployable), then verifies the chosen candidate on the full set. - Budgets (s1-style budget forcing on
</think>=248069):no_think(enable_thinking=False),think_{256,512,1024,2048},think_unbudgeted. Greedy (deployable pass@1) + k=8 sampled candidates (oracle ceiling). Thinking decode temp 0.6/top_p0.95/top_k20; no-think 0.7/0.8/20. - Baseline:
no_think(the corpus's universal setting). - Controls (planned follow-up run,
--controls): shuffled-thinking and truncated-thinking (isolate thinking content from the scaffold + compute); matched-total-token comparison. - Primary metric (deployable): greedy pass@1 and visible-test selector@1 vs budget.
- Oracle-only metrics: pass@k (k=8) — labeled non-deployable (uses hidden test outcomes to pick).
- Hidden-label boundary: pass@k and any "oracle" selection use hidden test results and are reported separately from deployable (greedy / visible-test-only) numbers.
Run
Smoke (proves the path; ~5 min):
.venv/bin/python scripts/run.py --smokeFull (background; ~hours on one RTX 4090):
HF_HUB_OFFLINE=1 PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True \
.venv/bin/python scripts/run.py --tasks 100 --k 8 \
--budgets no_think,256,512,1024,2048,unbudgeted --out runs/main
# then
.venv/bin/python analysis/analyze.py --tag mainGeneration (GPU) and verification (a separate torch-free process, so candidate-sandbox forks never inherit a CUDA context) are split inside run.py.
Results
Full results, controls, and limitations in reports/report.md. Headline (n=100 MBPP, k=8), deployable greedy pass@1 by thinking budget:
| no_think | think_256 | think_512 | think_1024 | think_2048 | unbudgeted |
|---|---|---|---|---|---|
| 0.760 | 0.870 | 0.870 | 0.910 | 0.860 | 0.840 |
- Native thinking is a deployable win the corpus disabled: greedy +15pp (0.76→0.91), moving the deployable line more than the oracle ceiling (pass@8 +5pp, 0.91→0.96) and closing the selection gap — opposite of the C2-based prior. Paired: 17 fail→pass vs 2 pass→fail (McNemar p≈0.001).
- Not monotonic: broad optimum ~512–1024 then decline;
unbudgeted(0.84) < a cap (0.91). - Scales with difficulty: +22pp on middling tasks (n=40); +33pp on never-solved (n=9, suggestive).
- Shuffled-thinking control: scrambling the model's own thinking reproduces much of the gain (so a large share is scaffold + compute + token-presence); evidence that coherent reasoning order adds more is weak/budget-dependent. Numbers independently recomputed from raw data + audited.
Interpretation
For a 4B on basic code, native thinking buys real deployable capability the corpus forfeited by construction, and it reframes C2 (here the deployable line moves, not just coverage). But the shuffle control shows much of the "thinking" benefit is compute/scaffold rather than coherent reasoning. The practical knob is a thinking budget with a real overthinking cost — motivating a learned budget controller and a stronger content control (program backlog).
Knowledgebase Update
- Program evidence updated: yes (
research_programs/test_time_reasoning_budget/evidence.md). - Program backlog updated: yes (controller, distillation, silent-executor budget sweep, stronger content control, thinking-as-verifier).
- Claim ledger updated: yes (C9, see
knowledge/claims/).
Artifacts
src/runtime (model + budget forcing), tasks (MBPP + sandbox verifier), metrics.scripts/run (sweep), verify_runs (torch-free verification), launch_main, status.configs/default sweep config.runs/per-runsummary.json,generations.jsonl,verified.jsonl(raw small artifacts).analysis/analyze.py, generated tables and figures.reports/final report +artifact_manifest.yaml.- Model weights are external (HF cache), not committed; see
reports/artifact_manifest.yaml.
Report
Rendered from reports/report.md
Summary
The imported 155-experiment corpus runs Qwen3.5-4B exclusively in no-think mode (enable_thinking=False ×48, True ×0 besides one fixed-768-token CoT foil) and treats "budget" as evidence/probe/sample budget, never the model's native reasoning-token budget. We turn thinking on and sweep the thinking budget on MBPP, decomposing the deployable line (greedy / visible-test-selected pass@1) from the oracle ceiling (pass@8). Three findings: (1) native thinking is a large deployable win the corpus forfeited — greedy pass@1 0.76 → 0.91 (+15pp), with the deployable gain exceeding the oracle-ceiling gain and closing the selection gap (opposite of our C2-based prior); (2) more thinking is not monotonically better — accuracy rises to a broad optimum around 512–1024 tokens and then declines, so the naive unbudgeted default (greedy 0.84) is worse than a capped budget (0.91), a rise-then-fall shape that holds across both greedy and sampled pass@1; (3) a shuffled-thinking control reproduces much of the gain — scrambling the model's own thinking tokens still recovers most of the lift — so a large share of the benefit is "scaffold + extra compute + relevant-token-presence," and the evidence that coherent reasoning order adds beyond that is weak and budget-dependent.
Research Program Fit
First experiment of test_time_reasoning_budget. It establishes the reasoning-token budget as a real, controllable test-time-compute axis (a verified corpus-wide blind spot) and motivates the program's controller / distillation / thinking-as-verifier lines. It also pressure-tests the corpus's "silent latent compute beats CoT" framing (qwen_python_shaped_silent_executor) and its central selection bottleneck (C2).
Method
- Model: Qwen/Qwen3.5-4B (the repo standard;
Qwen3_5ForCausalLM, bf16, sdpa), frozen. - Benchmark: MBPP sanitized,
testsplit (held out), first 100 tasks. Each task = NL spec → one Python function, checked against its 3–5asserts (median 3). - Protocol: prompt = NL spec + one example assert (signature anchor); a candidate passes iff it executes and satisfies the full
test_listin a sandboxed subprocess (fork, CPU/AS rlimits, 10s timeout + one retry to remove load-induced jitter). - Independent variable — thinking budget (s1-style budget forcing on
</think>=248069):no_think,think_{256,512,1024,2048}(cap thinking at B tokens; if</think>is not emitted, inject it and regenerate the answer),think_unbudgeted(cap 4096, no forcing). - Decoding: Qwen presets — thinking temp 0.6/top_p 0.95/top_k 20; no-think 0.7/0.8/20. Greedy (deployable pass@1) + k=8 sampled candidates (oracle pass@8).
- Controls: shuffled-thinking at 512 and 2048 — permute the model's own thinking tokens before forcing the answer (same token count, same multiset, same scaffold; coherent order destroyed). Isolates reasoning content from compute + scaffold + token-presence.
Results
Main sweep (n=100, k=8)
| budget | think tok | greedy@1 | sampled pass@1 | visible-sel@1 | pass@8 (oracle) | forced-close |
|---|---|---|---|---|---|---|
| no_think | 0 | 0.760 | 0.776 | 0.840 | 0.910 | 0.00 |
| think_256 | 246 | 0.870 | 0.833 | 0.880 | 0.930 | 0.85 |
| think_512 | 408 | 0.870 | 0.858 | 0.890 | 0.940 | 0.42 |
| think_1024 | 530 | 0.910 | 0.879 | 0.910 | 0.960 | 0.13 |
| think_2048 | 629 | 0.860 | 0.864 | 0.920 | 0.960 | 0.07 |
| think_unbudgeted | 572 | 0.840 | 0.864 | 0.920 | 0.950 | 0.00 |
Figures: analysis/main_scaling_curve.png, analysis/main_accuracy_vs_compute.png, analysis/main_passk_vs_k.png.
Finding 1 — thinking is a deployable win, not just a ceiling win
Greedy deployable pass@1 rises 0.76 → 0.91 (+15pp); visible-selector +8pp. The oracle ceiling rises only +5pp (0.91 → 0.96 — little headroom). So thinking closes the oracle−deployable gap (0.07 → 0.03–0.05), the opposite of our prior (from C2 we expected thinking to inflate coverage but not deployment). Robust on a paired basis: at think_1024 vs no_think, 17 tasks flip fail→pass and only 2 pass→fail (McNemar on 17/2 discordant pairs → p≈0.001).
Finding 2 — more thinking is not monotonically better (a broad optimum, then decline)
Deployable greedy rises to a broad optimum around 512–1024 tokens (think_1024 0.910 is the single best cell) and then declines at think_2048 (0.860) and think_unbudgeted (0.840). Sampled pass@1 traces the same shape (0.776 → 0.833 → 0.858 → 0.879 → 0.864 → 0.864, peaking at 1024). Forced-close fraction (0.85 → 0.42 → 0.13 → 0.07) shows the model "wants" ~500–1000 thinking tokens; forcing below costs accuracy, but letting it run free (unbudgeted) is worse than a cap. The oracle ceiling plateaus at ~0.96. Caveat: gaps among the thinking budgets are 2–7pp at n=100 single-seed, so we do not pin the optimum to exactly 1024 — but the rise-then-fall shape is corroborated across two metrics (greedy and pass@1), and the actionable lesson is robust: cap thinking; do not deploy unbudgeted.
Finding 3 — thinking's gain scales with task difficulty
Greedy, sliced by no-think oracle pass@8, comparing no_think to a fixed think_1024 budget (using a fixed budget rather than a per-bucket argmax avoids selection bias; think_1024 happens to be the best or tied cell in every bucket):
| no_think difficulty | n | no_think greedy | think_1024 greedy | Δ |
|---|---|---|---|---|
| already easy (8/8) | 51 | 0.941 | 1.000 | +0.06 |
| middling (1–7/8) | 40 | 0.700 | 0.925 | +0.23 |
| never solved (0/8) | 9 | 0.000 | 0.333 | +0.33 |
The benefit grows with difficulty. The robust part is the middling bucket (n=40): +22pp. The never-solved bucket is only 9 tasks (3 of 9 become greedy-solvable), so treat +0.33 as suggestive — but it does indicate thinking helps the model solve tasks it otherwise fails on every sample, i.e. some genuine capability, not only re-selection.
Controls
Shuffled-thinking (content vs compute), greedy@1:
| budget | no_think | shuffled thinking | real thinking |
|---|---|---|---|
| 512 | 0.760 | 0.800 | 0.870 |
| 2048 | 0.760 | 0.860 | 0.860 |
The striking result is how much of the gain scrambled thinking reproduces. At 512, shuffling the model's own thinking tokens still recovers 0.76 → 0.80 of the 0.76 → 0.87 greedy lift (~⅓ of the greedy gain from scaffold + compute + relevant-token-presence alone); at 2048, shuffled equals real (0.86 = 0.86) and even slightly exceeds it on sampled pass@1 (0.866 vs 0.864). So a large share of the "thinking" benefit for this small model on this task is not coherent reasoning — it is the extra forward compute, the <think> scaffold, and having relevant tokens in context. The evidence that coherent reasoning order adds beyond that is weak and budget-dependent: a ~7pp greedy edge at 512 (within single-seed noise; and only ~1pp on the more robust sampled pass@1) that disappears by 2048. This is the report's most provocative and most caveated result; a stronger control (substitute a different task's thinking, destroying token-presence too) is needed to settle how much is genuine reasoning.
Oracle Versus Deployable Evidence
Deployable (visible-only): greedy@1 and visible-selector@1 — these carry the headline. Oracle (non-deployable, uses hidden test outcomes): pass@8 — reported only as a ceiling. Unusually for this corpus, the deployable metric moved more than the oracle ceiling, and the gap narrowed with thinking. No hidden-label leakage into deployable numbers.
Interpretation
For a 4B on basic code, native thinking buys real deployable capability the corpus discarded by construction. It also reframes C2 (coverage ≫ deployable selection): for the thinking axis on MBPP, C2 does not hold — thinking moves the deployable line and closes the gap. The practical knob is a budget with a clear optimum (~1024) and a real overthinking cost, directly motivating a learned thinking-budget controller.
Limitations
- One benchmark (code), one difficulty band ("basic" Python), n=100, one model, single seed/cell. Differences ≲7pp are within unpaired noise; the large effects and paired flip counts are robust, the exact optimum (1024) is suggestive.
- The shuffle control destroys token order but not presence (same multiset incl. any partial answer fragments), so it understates the content contribution; substituting a different task's thinking is the stronger control.
- Throughput: Qwen3.5-4B's linear-attention ran in the slow torch fallback (fast path needs
causal-conv1d, buildable with the on-box CUDA 13.2 toolkit; deferred). Cost was generation time, not GPU memory.
Next Experiments
- Thinking-budget sweep on
qwen_python_shaped_silent_executor(its CoT collapsed to 0% at len-24 at a fixed 768 budget — does ≥1024 thinking rescue it?). - Learned STOP/MORE controller over the thinking budget vs the fixed ~1024 optimum.
- Stronger content control: substitute a different task's thinking (destroy token-presence too).
- Harder substrates (full MBPP, LiveCodeBench, math): does the optimum move, does C2 reappear?
- Thinking-as-verifier vs thinking-as-generator under matched token budget.
Artifact Manifest
See artifact_manifest.yaml. Model weights are external (HF cache, ~9.3 GB); small run artifacts (runs/*/summary.json, generations.jsonl, verified.jsonl) are kept in-repo.
Reproducibility
HF_HUB_OFFLINE=1 PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True \
.venv/bin/python scripts/run.py --tasks 100 --k 8 \
--budgets no_think,256,512,1024,2048,unbudgeted --out runs/main
.venv/bin/python scripts/run.py --tasks 100 --k 8 --only-controls --out runs/controls
.venv/bin/python analysis/analyze.py --tag main
.venv/bin/python analysis/analyze.py --tag controls
.venv/bin/python analysis/deeper_analysis.py --tag mainEnv: torch 2.12.1+cu130, transformers 5.12.1 (native qwen3_5), single RTX 4090 (24 GB), WSL.
Refinement (added after the foreign-thinking control)
This report's "much of the gain is scaffold + compute, not coherent reasoning" (Finding 3 / shuffle control) was later found overstated. A foreign-task-thinking ladder (qwen35_4b_thinking_content_vs_compute) showed the model uses thinking as content (splicing a different task's thinking collapses accuracy to ~4% — it solves the wrong problem), that scrambled thinking ≈ no-think on sampled full-pass (the "shuffle recovers ~⅓" here was a greedy-metric artifact), and that coherent thinking adds +12pp at the 512 budget. A later budget sweep (qwen35_4b_overthinking_content_ladder) went further: the coherence advantage grows with budget (+0.105 → +0.150 at 512→2048) and pure-compute filler ≈ no-think everywhere, so the gain is coherent reasoning at every budget. Notably, this report's own "2048 shuffle ≈ real" was a shuffle-protocol artifact — that run shuffled a fresh thinking sample; the tighter ladder (reusing real's exact tokens) shows real ≫ shuffle at 2048. See claim C9 for the corrected statement.
Experiment log 8
Show the running log (8 entries)
Scaffold
Created as a new experiment under the new test_time_reasoning_budget program.
Environment (RTX 4090 / WSL, migrated box)
The box arrived without a working ML env (the old vllm/env venv was broken: built for py3.10 but its python symlinked to system 3.12). System python lacked ensurepip, so python3 -m venv failed. Resolution: installed uv (no sudo) and created a standard project .venv. Stack: torch 2.12.1+cu130 (CUDA OK on the 4090), transformers 5.12.1 (natively supports qwen3_5), datasets 5.0.0, accelerate, bitsandbytes, matplotlib, pandas, flash-linear-attention 0.5.1.
Model
- Qwen/Qwen3.5-4B is the repo standard and is used here. (An earlier detour to the older Qwen3-4B was a mistake and was reverted — only the repo's current model is valid.)
- Qwen3.5-4B is
model_type: qwen3_5, a hybrid linear-attention + multimodal model (Qwen3_5ForCausalLMfor text). Loads viaAutoModelForCausalLM(trust_remote_code=True, dtype=bfloat16), ~8.4 GB VRAM. The cached copy on the box was tokenizer-only (~13 MB); full weights (~9.3 GB) were downloaded. - Think-token ids differ from Qwen3-4B: verified empirically
<think>=248068,</think>=248069 (vocab 248320). Using Qwen3-4B's ids (151667/151668) would silently break budget forcing.
Harness
src/runtime.py: prompts (system+user,enable_thinkingtoggle), batched generation, s1-style thinking-budget forcing (cap thinking at B tokens; if</think>not emitted, inject it and regenerate the answer), shuffled-thinking control, OOM-resilient batching (auto-subdivide on CUDA OOM).src/tasks.py: MBPP sanitized loader + sandboxed execution verifier (subprocess, rlimits, timeout) + code extraction. Verifier runs in a separate torch-free process (scripts/verify_runs.py) because forking candidate sandboxes from the CUDA process triggered MemoryError (a fork of an 8 GB+CUDA process under a 2 GB AS rlimit).src/metrics.py: unbiased pass@k + deployable (greedy, visible-test selector) vs oracle.scripts/run.py: GPU generation phase → writes generations.jsonl → spawns torch-free verification → summary.json.analysis/analyze.py: tables + scaling-curve figures.
Smoke / sanity
- Smoke (5 tasks, no_think+think_512, k=2) validated the full path. Early shape: thinking lifted greedy 0.60→1.00 and pass@2 0.80→1.00 while the visible-selector stayed 0.60 (the C2 oracle-vs-deployable gap this experiment is built to measure) — far too few tasks to conclude.
- Long-budget sanity (1024/2048/unbudgeted) confirmed no OOM and natural termination; easy tasks finish thinking in ~450–570 tokens, so forcing only bites at B≤512.
Throughput finding (a documented lesson)
Qwen3.5-4B's linear-attention layers run in a slow torch fallback: the fast path needs BOTH flash-linear-attention AND causal-conv1d. fla installed cleanly; causal-conv1d needs CUDA-toolkit compilation (nvcc 13.2 is present at /usr/local/cuda-13.2, so it is buildable — deferred as a throughput optimization for future program runs). Without it, aggregate decode is ~368 tok/s at batch 32 (~11 tok/s/seq), GPU util ~34% (kernel-bound, not batch-bound). First OOM came from batch 64 + no expandable_segments; fixed with conservative→ moderate batches, PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True, and OOM auto-subdivision.
Main run
Launched: 100 MBPP test tasks, k=8, budgets {no_think, 256, 512, 1024, 2048, unbudgeted}, deployable greedy + oracle pass@k, output runs/main/. Generation took ~8.6h (the linear-attention fallback + batch-gating by the slowest sequence; unbudgeted alone was 3.6h). Controls (shuffled-thinking at 512/2048) ran after, via scripts/finish_experiment.sh.
Results (see reports/report.md)
Deployable greedy pass@1: no_think 0.76 → think_1024 0.91 (+15pp) → 2048 0.86 → unbudgeted 0.84. Oracle pass@8: 0.91 → 0.96. Deployable moved more than oracle; selection gap narrowed; paired 17 fail→pass vs 2 pass→fail at think_1024 (McNemar p≈0.001). Non-monotonic (overthinking). Shuffle control: scrambled thinking reproduces much of the gain (shuffle_512 0.80, shuffle_2048 0.86 ≈ real 0.86) — a large share is compute/scaffold, not coherent reasoning.
All headline numbers were independently recomputed from raw verified.jsonl and audited by a separate verification workflow (transcription clean; the audit's overclaim flags — exact-1024 optimum, argmax-over-budgets difficulty deltas, half/half content split — were folded into the final report as hedges). A verification jitter (±1–2pp from timeout-sensitivity under GPU load) motivated the verifier's retry-on-timeout; final numbers were verified with no competing GPU job.
Figures 6
Data files 2
Result tables and metrics copied from the experiment folder — preview inline or open the raw file.
Reproduce
Smoke test
HF_HUB_OFFLINE=1 ../../.venv/bin/python scripts/run.py --smokeFull run
HF_HUB_OFFLINE=1 PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True ../../.venv/bin/python scripts/run.py --tasks 100 --k 8 --budgets no_think,256,512,1024,2048,unbudgeted --out runs/mainRun steps are documented inside the experiment folder (README and scripts).





