# Solving IMO Problems with Five Minds and a Confident Consensus Competition: AI Mathematical Olympiad — Progress Prize 3 Final score: 40.5 / 50 Model: GPT-OSS-120B Approach: Hybrid parallel-sequential scaling with difficulty-aware time budgeting and cross-family entropy voting The most surprising thing I learned building this solution is not what made it work it's what made it stop working every time I tried to make it better. Ten notebook versions. Scores ranging from 8 to 38. Same model throughout. Every time I added something that seemed like a clear improvement a verifier, a Bayesian prior, a smarter confidence scorer, minority answer protection the score went down. The version that scored best was also the simplest one I ran after getting the fundamentals right. This writeup describes that pipeline in full detail, and then explains what I learned from the nine other versions that didn't work The Core Idea: Let Five Different Thinkers Solve the Same Problem The central bet in this version is that reasoning diversity beats reasoning depth. Instead of asking one highly-instructed solver to think harder, I ask five structurally different solvers to think independently — then let a confidence-weighted vote decide which answer to trust. This works because hard olympiad problems have many failure modes. A solver that reasons analytically might misread a combinatorial constraint. A solver that jumps to code might conjecture a pattern that doesn't hold. A solver that over-verifies might invalidate its own correct intermediate result. No single strategy is safe. But if five structurally uncorrelated strategies all land on the same answer, that agreement is strong evidence The architecture has three layers: Parallel layer : 15 attempts run concurrently across 5 prompt families (3 attempts each), 16 worker threads Sequential layer : each attempt runs an independent multi-turn Tool-Integrated Reasoning (TIR) loop against a live Python sandbox Selection layer : entropy-weighted voting with a cross-family bonus and a repair fallback ![](assets/aaf6ebd370aa3e309013271f.jpg) Full end-to-end workflow of Version 73. Problem input fans out into 15 parallel attempts across 5 prompt families. Each attempt runs a sequential TIR loop streaming tokens, executing Python in a sandbox, detecting the boxed answer, and accumulating logprobs. Completed attempts feed into entropy-weighted answer selection. If no valid answer is found across all 15 tasks, a repair loop fires 3 brute-force-first attempts as a fallback. The Infrastructure Model and Serving GPT-OSS-120B (danielhanchen/gpt-oss-120b) served via a vLLM OpenAI-compatible server. The most important serving decision is using FP8 KV cache (kv_cache_dtype = 'fp8_e4m3') at a 65K context window rather than the model's native 131K. This roughly doubles effective batch concurrency — more parallel attempts complete within the time budget. Wider context sounds better on paper, but fewer completed attempts means a weaker voting pool. Throughput wins. served_model_name = 'gpt-oss' kv_cache_dtype = 'fp8_e4m3' context_tokens = 65536 batch_size = 256 gpu_memory_utilization = 0.94 Server flags: --async-scheduling, --enable-prefix-caching, --disable-log-stats. Weights are preloaded into the OS page cache before server startup by reading all shard files in parallel across 16 threads — this shaves ~30s off cold-start time. The Python Sandbox Pool Every attempt runs inside an isolated ComputationSandbox — a persistent Jupyter kernel managed via jupyter_client.KernelManager. A pool of 16 sandboxes is initialised in parallel at startup. Between attempts, sandboxes are reset via %reset -f rather than shut down and recreated — this saves the ~2s kernel startup cost per attempt, which compounds across 50 problems × 15 attempts. Each sandbox runs a warm-up assertion on init: import math, numpy, sympy, itertools, collections, mpmath mpmath.mp.dps = 64 assert sympy.isprime(7), "sympy broken" assert float(mpmath.sqrt(2)) > 1.4, "mpmath broken" print("sandbox_ok") If sandbox_ok is absent, the sandbox is rejected before entering service. This catches broken kernels before they silently corrupt attempts. The Tool-Integrated Reasoning Loop The openai_harmony library handles multi-turn conversation encoding. This is not just a convenience wrapper — it provides a typed message protocol with structured channels (recipient == 'python', channel == 'final') that the model uses to signal tool requests and final answers. Dropping this protocol (as I did in Version 91) is catastrophic because the model loses its ability to reliably signal when it has finished versus when it is still reasoning. Each attempt runs up to 128 turns: Render conversation → prompt token IDs via encoding.render_conversation_for_completion Stream completion from vLLM, collecting token IDs, text fragments, top_logprobs=5 per token On every } in the stream: check rolling 32-token buffer for \boxed{N} Parse tokens → new messages via encoding.parse_messages_from_completion_tokens If recipient == 'python' → execute code in sandbox, append output to conversation If channel == 'final' → extract answer, break If context remaining < 512 tokens → break Token-level log probabilities accumulate across all turns for the entropy computation used in voting. Difficulty-Aware Time Budgeting One of the quieter but important decisions: per-problem time budget adjusts dynamically rather than being fixed. elapsed = time.time() - self.start_time rem_time = 17400 - elapsed reserve = max(0, self.remaining - 1) * 300 # 300s reserved per remaining problem budget = min(max(rem_time - reserve, 300), 900) deadline = time.time() + budget Problems early in the notebook get a generous budget when time is plentiful. Problems late in the notebook get a tighter budget to protect time for the remaining ones. Every streaming loop and turn boundary checks stop.is_set() or time.time() > deadline — attempts cancel gracefully rather than getting killed mid-execution. The Five Reasoning Families This is the heart of Version 73. Each family is not just a differently-worded prompt — it's a different reasoning philosophy that produces structurally uncorrelated solution trajectories. The goal is for each family to fail on different problems, so that across 15 attempts, no failure mode dominates. Family 1 — Structured Phase Reasoning The most methodical family. Four mandatory phases in sequence: UNDERSTAND (restate problem, enumerate every constraint, identify domain) → PLAN (write 2–3 candidate strategies, choose one with justification) → EXECUTE (step-by-step with Python for anything >3 manual steps) → VERIFY (plug answer back into every constraint from Phase 1; if any check fails, return to PLAN). This family is the constraint-checker of the pool. It is most likely to catch answers that are mathematically correct but violate an implicit boundary condition. The VERIFY phase returning to PLAN on failure turns it into a local search loop within a single attempt. You are an elite IMO/AIME mathematician. Follow these FOUR phases strictly: PHASE 1 – UNDERSTAND • Restate the problem in your own words. • List every given constraint and what is being asked. • Identify the mathematical domain (number theory, combinatorics, algebra, geometry…). PHASE 2 – PLAN • Write down 2–3 candidate solution strategies. • Briefly argue why each might work or fail. • Choose the most promising strategy and explain why. PHASE 3 – EXECUTE • Carry out the chosen strategy with explicit algebraic/logical steps. • Use Python for any computation longer than 3 manual steps. • Show intermediate results clearly. PHASE 4 – VERIFY • Plug your answer back into EVERY constraint stated in Phase 1. • If any check fails, return to Phase 2 with a revised strategy. • Confirm the answer is a non-negative integer in [0, 99999]. Output the answer ONLY as: \boxed{N} (nothing after this line) Available Python libs: math, numpy, sympy, itertools, collections, mpmath (dps=64). Family 2 — Adversarial Self-Critic The model acts as both solver and harshest critic. After a first-pass solution, it runs an explicit adversarial review: did I misread a constraint? Is my domain assumption correct (integers vs. reals, inclusive vs. exclusive bounds)? Off-by-one? Answer satisfies ALL conditions, not just the main equation? If any flaw is found, it re-solves. If none, a Python sanity check must confirm before output is allowed. This family catches a specific failure mode that the other four miss: the model convincing itself a wrong answer is correct through plausible but flawed reasoning. The adversarial step exists to find holes in that reasoning from the outside. You are a rigorous mathematical solver AND your own harshest critic. STEP 1 – FIRST SOLUTION ATTEMPT Solve the problem carefully using algebra, number theory, or combinatorics. Use Python to handle any non-trivial computation. STEP 2 – ADVERSARIAL CRITIQUE Act as a skeptical reviewer. Ask yourself: • Did I misread any constraint? • Is my domain assumption correct (integers vs reals, inclusive vs exclusive bounds…)? • Could there be edge cases or off-by-one errors? • Does my answer satisfy ALL conditions, not just the main equation? STEP 3 – REVISION OR CONFIRMATION If the critique found any flaw, fix it and re-solve. If no flaw found, confirm the answer with a Python sanity check. Output the answer ONLY as: \boxed{N} (nothing after this line) Available Python libs: math, numpy, sympy, itertools, collections, mpmath (dps=64). Family 3 — Computational-First Enumerate before you theorise. The mandatory sequence: PARSE → BRUTE-FORCE SMALL CASES (print a Python table of results for small n) → CONJECTURE (closed-form or recurrence from data) → PROVE OR VALIDATE (exhaustive check or proof; "the pattern matches small cases" is not accepted) → COMPUTE FINAL ANSWER → CROSS-CHECK (re-run brute-force for exact input and compare). This family is the most reliable on number theory and combinatorics problems where a pattern exists to be discovered. Mandating computation before analysis prevents premature analytical commitment — the failure mode of being so certain about a formula that you don't check it. You are an expert at solving olympiad problems through guided computation. WORKFLOW: 1. PARSE – Identify parameters, bounds, and the quantity to compute. 2. BRUTE-FORCE SMALL CASES – Use Python to compute answers for small inputs. Print a table of results to spot patterns. 3. CONJECTURE – Formulate a closed-form or recurrence based on observed data. 4. PROVE OR VALIDATE – Either prove the conjecture mathematically, or verify it exhaustively across all valid inputs if the search space allows. 5. COMPUTE FINAL ANSWER – Apply the validated formula/recurrence to the given input. 6. CROSS-CHECK – Re-run the brute-force for the exact input if feasible; compare. Always prefer verified computation over unverified closed-form guesses. Output the answer ONLY as: \boxed{N} (nothing after this line) Available Python libs: math, numpy, sympy, itertools, collections, mpmath (dps=64). Family 4 — Meta-Strategy Selector Before solving, classify the problem into a domain: NUMBER THEORY (CRT, prime factorisation, modular arithmetic) / COMBINATORICS (generating functions, inclusion-exclusion, DP, bijection) / ALGEBRA (polynomial roots, Vieta's, functional equations) / GEOMETRY (coordinates, trigonometry, area ratios) / MIXED (decompose). Then commit to a specific named technique and execute. The classification step matters because hard olympiad problems often disguise their domain. A sum over divisors looks algebraic but is number theory. A path count on a grid looks geometric but is combinatorics. Forcing explicit domain commitment before execution reduces mid-solution strategy drift, which is a common source of partial and incorrect answers. You are an olympiad problem-solving strategist. Before solving, CLASSIFY the problem and select the optimal technique: CLASSIFICATION (choose one): A. NUMBER THEORY → use modular arithmetic, Chinese Remainder Theorem, prime factorisation. B. COMBINATORICS → use generating functions, inclusion-exclusion, DP, bijection. C. ALGEBRA → use polynomial roots, Vieta's, inequalities, functional equations. D. GEOMETRY → use coordinates, trigonometry, area ratios, projective methods. E. MIXED / OTHER → decompose into sub-problems and apply relevant techniques. SOLUTION PROTOCOL: 1. State the classification and your chosen technique with one-line justification. 2. Set up the mathematical framework precisely. 3. Solve step-by-step; use Python for symbolic algebra or heavy computation. 4. State the answer and verify it satisfies every constraint. Output the answer ONLY as: \boxed{N} (nothing after this line) Available Python libs: math, numpy, sympy, itertools, collections, mpmath (dps=64). Family 5 — Decomposition + Subgoal Chaining Break the problem into 3–5 precise mathematical subgoals. Solve each in sequence, labelling results [SG1 result], [SG2 result], … Combine them explicitly in a synthesis step showing every substitution. End with a Python end-to-end check that reproduces the final answer from inputs. This family is strongest on multi-step algebra and geometry problems where a long direct solution is error-prone but a chain of smaller lemmas is tractable. The labelled subgoal structure keeps long solutions coherent and makes the synthesis auditable. The end-to-end Python check catches synthesis errors — places where two correct subgoals combine incorrectly. You are a mathematical olympiad expert who solves hard problems by decomposing them into a chain of simpler subgoals. PROCESS: SUBGOAL DECOMPOSITION • Break the problem into 3–5 independent or sequential subgoals. • Write each subgoal as a precise mathematical statement. SUBGOAL SOLVING • Solve each subgoal in order. Label results clearly: [SG1 result], [SG2 result], … • Use Python for any subgoal requiring non-trivial calculation. SYNTHESIS • Combine subgoal results to obtain the final answer. • Show the synthesis step explicitly. FINAL VERIFICATION • Run a Python end-to-end check: given all inputs, does your code reproduce the answer? Output the answer ONLY as: \boxed{N} (nothing after this line) Available Python libs: math, numpy, sympy, itertools, collections, mpmath (dps=64). The Voting System: Why One Clever Vote Beats Many Simple Ones The Formula After all 15 attempts complete (or early stop fires), every candidate answer gets a score: score(a) = freq_score(a) + 2.0 × entropy_score(a) × cross_prompt_multiplier(a) × suspect_penalty(a) freq_score(a) = count(a) / total_valid_attempts entropy_score(a) = avg_inv_entropy(a) / global_sum_inv_entropy What Each Piece Does Frequency score is plain majority voting. It is the floor, not the ceiling — on its own it is vulnerable to correlated errors across attempts of the same family. Inverse entropy score measures how confident the model was token-by-token when producing a given answer. Low entropy near the final tokens means the model's probability mass was concentrated — it wasn't hedging. This signal, weighted at 2×, distinguishes "I calculated this carefully and I'm sure" from "this seems plausible." Cross-prompt family bonus (1.5×) fires when two or more structurally different families agree. An answer reached independently by both the Computational-First family (via brute-force pattern discovery) and the Adversarial-Critic family (via constraint checking after solving) is worth far more than three attempts of the same family agreeing. This single component is the most important addition over plain entropy voting. Suspect-answer penalty (0.3×) suppresses the most common wrong-answer failure modes. Values in {0, 1, 2, 99999, 100000} and non-zero multiples of 1000 appear disproportionately as default outputs from failed computations. They are rarely correct olympiad answers. Early Stopping When 5 or more attempts agree on the same answer at ≥60% vote share, early stop fires, the threading stop event is set, and pending futures are cancelled. This saves 30–120 seconds on easy problems — compounding over 50 problems, it buys meaningful additional budget for the hard ones. The Repair Loop On the rare problems where all 15 attempts produce zero valid \boxed{N}, three repair attempts fire with a different prompt that mandates Python brute-force as the first action, prints progress during search, and explicitly lists six failure modes to avoid. Repair attempts get prompt_id = -1 and are excluded from the cross-prompt family bonus so they cannot inflate a weak consensus. You are solving a competition mathematics problem. Previous automated attempts all FAILED to produce a valid answer. You must now try a completely different approach. STRICT RULES: 1. Do NOT repeat any approach that requires long symbolic manipulation without Python. 2. Your FIRST action must be a Python brute-force or exhaustive search, even if the search space seems large — use heuristics to limit it if needed. 3. Print candidate answers during the search so partial progress is visible. 4. After getting a numeric candidate, verify it independently with a second Python script. 5. Your answer MUST be a non-negative integer in [0, 99999]. COMMON FAILURE REASONS TO AVOID: • Off-by-one in loop bounds (use inclusive endpoints carefully). • Misreading 'mod M' — the answer is the remainder, not the quotient. • Forgetting to take the final mod if the problem asks for answer mod N. • Treating a combinatorial count as a geometric/algebraic one or vice versa. Output the answer ONLY as: \boxed{N} (nothing after this line) Available Python libs: math, numpy, sympy, itertools, collections, mpmath (dps=64). Key Configuration ![](assets/d51660d404d9d3fda1ad0f66.png) Everything I Tried — And What Each One Taught Me I ran far more than 10 experiments across this competition. What I'm sharing here is a representative set of notebook versions that were similar enough to each other — in terms of prompt design, voting strategy, or workflow architecture — to make a clean comparison, plus one entirely separate direction I explored: fine-tuning the model itself. Each attempt isolates a different question about what actually drives performance. The headline across everything: the base model's reasoning capability is already strong. The question is never how to teach it more — it's how to sample from it more effectively. Inference Experiments ![](assets/4dc0670bbc72764854626020.png) What the Private Leaderboard Revealed Version 19 (−30 from Version 73): The most important data point. No tool calls — same model, same voting, same 15 attempts. Without Python access the model cannot verify arithmetic, enumerate small cases to spot patterns, or validate conjectures before committing. Tool-integrated reasoning is not an optimisation. It is the difference between this being a hard problem and an impossible one. Version 91 (−25 from Version 73): Three things broke simultaneously. The openai_harmony library was dropped in favour of raw client.completions.create PythonTool and ComputationSandbox were still there, but without the typed message protocol the model had no reliable way to signal completion vs. intermediate reasoning, so many attempts produced no valid \boxed{N}. Minority answer protection actively inverted consensus logic. The Contrarian prompt steered the model away from correct approaches on every attempt it was used. All three failed together. Version 39 (−14 from Version 73): Replaced the Harmony/vLLM-server stack with vLLM's direct Python API, single-pass generation via llm.generate(), and post-hoc code extraction via regex. The multi-turn feedback loop disappeared entirely the model could write code but couldn't see its output and revise. That loop is what makes TIR valuable. Without it, you're just generating text that happens to contain code. Version 49 (−9 from Version73): 50 total attempts, per-strategy temperatures, min_p raised to 0.06. With 16 workers and a 300–900s budget, most attempts after the 16th are queued and cancelled. More attempts is not better when the hardware can't actually run them. min_p=0.06 also cut lower-probability tokens that creative mathematical reasoning often needs. Version 92 (−6 from Version73): Added a 6th prompt family pushing to 18 total tasks last 3 frequently didn't complete on 16 workers. The verifier pass used its 1024-token budget for reasoning rather than the required CONFIRMED/CORRECTED output. It fired on nearly every problem and returned no usable signal. Version 95 (−5 from Version73): Laplace smoothing made a strong singleton indistinguishable from a weak majority. Verification bonus penalised iterative debugging attempts exactly the ones most likely to solve hard problems. Adding 42, 360, 720 to the suspect set incorrectly penalised valid olympiad answers. Version 98 (−4 from Version73): Reduced families from 5 to 2. The cross-prompt bonus needs structurally different families to fire — with 2 it barely fires at all. Mixed temperature 0.5/0.7 produced less diverse candidates. Version 74 (−3 from Version73): Temperature schedule [0.6, 1.0, 1.3] introduced low-temperature attempts that produced low-entropy wrong answers. The inverse-entropy voting mechanism amplified exactly those low entropy looked like confidence. Answer clustering with tolerance=2 merged distinct correct and incorrect nearby answers. Version 96 (−2 from Version73): Tightened prompts consumed 300–500 extra context tokens per attempt. On long problems attempts hit the context limit before completing. The extended adversarial checklist caused the model to revisit and invalidate correct intermediate results. The Three Tiers of Failure After seeing where each version landed on the private leaderboard, three clear patterns emerged: Tier 1 . Architectural breaks (−14 to −30): Removing tool access or breaking the TIR protocol. These are not tuning mistakes they change what the system fundamentally can do. Tier 2. Consensus interference (−5 to −25): Minority protection, Bayesian smoothing, verification bonuses. All share the same flaw they try to second-guess what the voting pool is already doing correctly. Tier 3. Resource competition (−2 to −9): Tighter prompts consuming context, more attempts than workers can handle, temperatures that reduce diversity. The Fine-Tuning Detour Alongside the inference experiments, I explored whether fine-tuning GPT-OSS-120B directly on competition-style problems could push the score further. Training setup: LoRA fine-tuning via Unsloth's FastLanguageModel with 4-bit quantization, using the nvidia/OpenMathReasoning TIR split (CoT files never downloaded to save RAM). Problems were filtered to pass_rate_72b_tir between 0.05 and 0.35 hard enough to learn from, solvable enough to have reliable ground truth with answers in [0, 99999] to match the competition format. Final sample: 3,500 examples. LoRA rank 16, alpha 32, targeting all projection modules, 1 epoch at learning rate 1e-4. The system prompt used during training was the same Computational-First prompt from Version 73 so the adapter would be aligned to the same reasoning style used at inference. Inference with adapter: The trained LoRA adapter was loaded alongside the base model via vLLM's --enable-lora flag, using the same Harmony TIR loop and entropy-weighted voting as Version 73. What happened: The fine-tuned version performed significantly worse on the unseen competition set. The likely reasons: Distribution mismatch : OpenMathReasoning's TIR split covers a different difficulty profile and problem style than AIMO3's hidden test set. The adapter learned reasoning patterns that didn't transfer to IMO-level problems. Boundary token sensitivity : the Harmony chat template injects a developer block before the user turn, making boundary token detection non-trivial. Any misalignment between training-time and inference-time prompt rendering can silently break the model's output format. Single reasoning style : the adapter was specialised to one prompt family, which meant Version 73's core advantage — five uncorrelated reasoning families voting was entirely lost. Overfitting to training distribution: Even with the matched prompt, the adapter appeared to have overfit to the style and difficulty of the OpenMathReasoning examples rather than developing generalisable problem-solving behaviour. The LoRA weights encoded surface patterns from the training set, not deeper reasoning strategies that transfer across problem families. This result settled the question definitively. The right investment was in the inference pipeline, not the model weights. Version 73 represents the endpoint of that inference-first approach. Trying Different Models Beyond GPT-OSS-120B, I explored whether smaller or differently-architected models could compete on this benchmark. Two were tested in full end-to-end pipelines. DeepSeek-R1-0528-Qwen3-8B An 8B reasoning model with a native thinking protocol. The pipeline used client.chat.completions.create directly no Harmony encoding library with a five step problem solving prompt (UNDERSTAND → EXPLORE → PLAN → EXECUTE → VERIFY), 8 parallel attempts at temperature 1.0, entropy-weighted voting, and a Jupyter sandbox pool for Python execution. Answer extraction handled both \boxed{N} and N formats. The key difference from Version 73 was the absence of the structured Harmony TIR protocol — tool calls were managed by extracting ` python blocks from assistant messages and feeding output back as a new user turn, which is architecturally similar to Version 39. The model performed significantly worse on the competition set. The 8B parameter count is the likely ceiling — at IMO difficulty, multi-step symbolic reasoning and pattern generalisation require a model with substantially more capacity. The post-hoc code-extraction approach also reintroduced the same feedback loop problem that hurt Version 39: the model writes code in one pass without seeing whether it succeeded before committing to a conclusion. Nvidia Nemotron-3-Nano-30B A 30B reasoning model with a built-in thinking protocol (… tags, enforced via chat_template_kwargs={"thinking": True}). The pipeline was more sophisticated than the DeepSeek attempt: context pruning when approaching the 65K limit, a repair prompt that fires when all primary attempts fail, a consecutive-no-progress early exit after 3 turns without code or answer, and min_tokens=2048 on the first turn to force a full reasoning chain. 6 parallel attempts, temperature 0.6, suspect-answer penalty (0.5× weight for {0, 1, 2, 99999, 100000}). This version performed better than the DeepSeek attempt but still fell well short of Version 73. The 30B parameter count is a meaningful step up but still substantially below GPT-OSS-120B's 120B. More significantly, the pipeline lacked the openai_harmony typed message protocol — without it, the model's thinking-channel output and final-answer signal were harder to parse reliably, and the conversation management relied on the same manual text-appending approach that caused problems in Version 91. What these experiments confirmed Both model experiments pointed to the same conclusion: at IMO difficulty, parameter count matters significantly, and the structured TIR protocol provided by openai_harmony is not just a convenience it is load-bearing infrastructure for reliable multi-turn tool interaction. Neither a capable smaller model nor a more sophisticated prompt design could compensate for those two factors. Architectural dimensions ![](assets/d7bfc307a3e13a0607463925.png) Every pipeline that lost either Harmony TIR or tool calls scored 24 or below. Conclusion The central lesson of this entire experiment is deceptively simple: the model already knows how to solve mathematics. The job of the pipeline is to ask it the same question five different ways, then trust the answer they agree on. Version 73 worked not because it had a smarter prompt or a more sophisticated voting mechanism than the versions that came before it — it worked because it had the right combination of three things that genuinely cannot be substituted for each other: Tool-integrated reasoning with a structured protocol. The 30-point gap between Version 73 and Version 19 (pure chain-of-thought, no tools) comes from a single architectural decision. Python access lets the model verify arithmetic, enumerate small cases to spot patterns, and validate conjectures before committing. The Harmony protocol ensures the model knows when it has finished versus when it is still reasoning. Without both, the model is guessing in the dark. Reasoning diversity over reasoning depth. Five structurally different prompt families produce uncorrelated failure modes. When two or more families independently agree on an answer — one via brute-force pattern discovery, another via constraint-checking adversarial critique — that cross-family consensus is strong evidence of correctness that simple majority voting cannot produce. Every time I reduced the number of families, or made individual prompts more elaborate and instruction-heavy, the score went down. Restraint in the voting layer. The voting function works because it stays close to its core: frequency plus confidence plus a cross-family bonus plus a mild penalty for suspicious values. Every elaboration I added — Bayesian smoothing, verification bonuses, minority protection, answer clustering — made things worse. The pool's job is to converge on right answers. Any mechanism that resists that convergence is harmful by construction. The experiments with other models (DeepSeek-R1-0528-Qwen3-8B, Nvidia Nemotron-3-Nano-30B) and the fine-tuning attempt all reinforced the same point: at IMO difficulty, parameter count and the quality of the inference infrastructure matter more than prompt engineering. GPT-OSS-120B with a clean TIR pipeline outperformed both smaller models with more elaborate prompting and the same model with a specialised LoRA adapter. If I were to continue this work, the direction I would explore is not better prompts or smarter voting — it is tree-search inference, where failed attempts inform subsequent ones within a single problem budget. That is the one architectural change that could meaningfully improve on Version 73 without risking the regressions that came from every other elaboration tried here. References AIMO Prize Foundation. AI Mathematical Olympiad Progress Prize 3. Kaggle Competition, 2026. OpenAI. GPT-OSS-120B. Hugging Face Model Hub, 2025/2026 Chan, Daniel (Unsloth). GPT-OSS-120B. Hugging Face Model Hub, 2026. Kwon, W. et al. Efficient Memory Management for Large Language Model Serving with PagedAttention. SOSP, 2023.