Deep Dive: Foundations & Training Systems
Transformers, scaling laws and compute-efficient training
Transformer internals from first principles
After this you can explain attention and the transformer block without notes.
Cursor's Research Scientist loop opens with fundamentals interviewers expect cold. If you stumble deriving attention or explaining why the KV cache eats inference memory, the rest of the conversation never reaches the interesting RL questions.
The bar here is not reciting the Attention Is All You Need abstract. It is reconstructing a transformer block from the matmuls up, knowing which design choices the ComposerCursor's own fast coding model, tuned for the editor and priced well below frontier models; the recommended day-to-day model for executing a plan. model family actually depends on and being able to reason about where the compute and the memory go when you serve it to millions of developers.
Self-attention from the matmuls upQ, K, V and why we scale
Each token's embedding is projected three ways: a query (what am I looking for), a key (what do I offer) and a value (what I pass along if attended to). The attention weight from token i to token j is the dot product of query i and key j, softmaxed across all keys, then used to mix the values.
import torch, torch.nn.functional as F
def attention(x, Wq, Wk, Wv, mask=None):
Q, K, V = x @ Wq, x @ Wk, x @ Wv # each (B, T, d_k)
d_k = Q.size(-1)
scores = (Q @ K.transpose(-2, -1)) / d_k ** 0.5 # (B, T, T)
if mask is not None: # causal: upper triangle = -inf
scores = scores.masked_fill(mask, float('-inf'))
w = F.softmax(scores, dim=-1) # rows sum to 1
return w @ V # (B, T, d_k)The / sqrt(d_k) is the part interviewers probe. Without it, dot products grow with dimension, so logits land far out on the softmax where gradients vanish and one key dominates. Dividing by sqrt(d_k) keeps the variance of the scores near 1 regardless of head width, which keeps the softmax in a regime where gradients actually flow.
When asked "why sqrt(d_k) and not d_k?", answer with the variance argument: if query and key entries are unit-variance and independent, their dot product over d_k terms has variance d_k, so dividing by sqrt(d_k) (the standard deviation) renormalizes to unit variance. Dividing by d_k would over-shrink the logits toward a uniform, low-signal softmax.
From one head to a blockmulti-head, residuals, norm placement, FFN
Multi-head attention runs several of these in parallel on lower-dimensional slices, then concatenates and projects back. Splitting the representation lets different heads specialize, one tracking syntax, another long-range references, without growing the total compute.
Interactive diagram. Tab through its regions; each focused region shows its detail in the panel below.
Each sublayer adds to a residual stream that runs straight through the block.
- Multi-head attention
- h heads of width d_model/h run in parallel, concatenate, then a final output projection. Same FLOPs as one wide head, but more specialization.
- Residual connections
- Each sublayer adds its output back to its input. This keeps a gradient highway open through deep stacks, so 60+ layers still train.
- LayerNorm placement
- Pre-norm (normalize before the sublayer) is the modern default: it stabilizes deep training without the warmup gymnastics post-norm needs.
- Feed-forward network
- A 2-layer MLP applied per position, usually ~4x d_model wide. This is where most parameters and most FLOPs live, not in attention.
The block is: x = x + attn(norm(x)) then x = x + ffn(norm(x)). Post-norm wraps the norm around the residual sum instead, which was the original design and is harder to train deep without careful warmup. If you say "pre-norm" and can explain why (gradient stability at depth), that reads as someone who has actually trained these.
Positional informationRoPE vs learned/absolute
Attention is permutation-invariant on its own, so position has to be injected. Learned absolute embeddings add a per-position vector and break the moment you exceed the trained length. RoPE (rotary position embeddings) instead rotates the query and key vectors by an angle proportional to position, so attention depends on the relative offset between tokens.
- Scheme
- Learned absolute
- How position enters
- Add a trained vector per index
- Long-context behavior
- Hard cap at trained length; no extrapolation
- Scheme
- Sinusoidal absolute
- How position enters
- Add fixed sin/cos of position
- Long-context behavior
- Extrapolates weakly; rarely used now
- Scheme
- RoPE (rotary)
- How position enters
- Rotate Q/K by position angle
- Long-context behavior
- Relative by construction; extends via base/NTK scaling
| Scheme | How position enters | Long-context behavior |
|---|---|---|
| Learned absolute | Add a trained vector per index | Hard cap at trained length; no extrapolation |
| Sinusoidal absolute | Add fixed sin/cos of position | Extrapolates weakly; rarely used now |
| RoPE (rotary) | Rotate Q/K by position angle | Relative by construction; extends via base/NTK scaling |
RoPE is the default in state-of-the-art code models because long agent-assisted sessions need context that extends past the trained window.
A Cursor agent editing a real repo carries file contents, tool outputs and many turns of history. Relative position via RoPE matters because the model must reason about a function defined 8,000 tokens earlier the same way whether it sits at position 8k or 80k. Absolute schemes would treat those as different.
Decoding and the KV cachewhere inference memory actually goes
Generation is autoregressive: one token at a time, each conditioned on all prior tokens through a causal mask. Recomputing every prior key and value at each step would be quadratic, so you cache them. The KV cache stores the keys and values for every past token across every layer and head.
- Causal mask
- Token t may only attend to positions <= t. During generation the new token attends to the whole cache.
- KV cache size
- Scales as 2 x layers x heads x head_dim x seq_len x batch. At long context this dwarfs the weights and caps how many concurrent users you serve.
- Sampling
- Temperature flattens or sharpens the logits; top-p keeps the smallest set of tokens covering probability p. Lower both when you want deterministic, tool-correct edits.
Ask any inference-cost question by starting with KV-cache memory, not parameter count.
A common miss is calling parameters the inference bottleneck. At long context with many concurrent sessions, the KV cache is what runs you out of GPU memory first. This is exactly why grouped-query attention and cache-eviction tricks exist and why a Cursor researcher serving long agent sessions cares about it.
Takeaway. A transformer block is residual attention plus a residual FFN under pre-norm; scale scores by sqrt(d_k) for stable gradients, use RoPE for relative position in long sessions and remember the KV cache - not the weights - usually caps inference at scale.
Self-check
QAttention divides the Q·K scores by sqrt(d_k). What goes wrong if you drop this scaling entirely?
Scaling laws and compute-optimal training
After this you can use scaling laws to reason about data, parameters and compute.
"Train with less compute" is in the job description and scaling laws are the language for spending a fixed FLOP budget well. Expect to be asked, on a whiteboard, how you'd allocate a budget between a bigger model and more data.
The headline result is Chinchilla: for a fixed training-compute budget, loss is minimized by scaling parameters and training tokens together, roughly in proportion, rather than pouring everything into a giant under-trained model. The earlier GPT-3-era models were large and badly under-trained on data.
The power law, in wordsloss vs compute
Test loss falls as a power law in compute: each doubling of FLOPs buys a steady, diminishing fractional improvement and on a log-log plot the loss-vs-compute curve is close to a straight line. The practical consequence is that you can fit the trend on small runs and predict where a large run will land before you spend the budget.
- C (compute)
- Training FLOPs, approximately 6 x N x D. The budget you actually control.
- N (parameters)
- Model size. More N raises capacity per step but costs more FLOPs per token.
- D (tokens)
- Training data seen. Chinchilla-optimal D grows roughly linearly with N.
- The rule of thumb
- Hold C fixed; the optimum scales N and D together. Doubling C means roughly sqrt(2) more params and sqrt(2) more tokens, not 2x params alone.
Training compute is about 6 x N x D FLOPs (2ND forward, 4ND backward). Memorize this. It lets you answer "can we afford this run?" and "if I halve the model, how much more data fits in the same budget?" on the spot, which is exactly the kind of back-of-envelope a Cursor research screen wants.
Compute-optimal is not the same as deployment-optimalthe inference twist
Chinchilla minimizes training loss per training FLOP. Cursor serves ComposerCursor's own fast coding model, tuned for the editor and priced well below frontier models; the recommended day-to-day model for executing a plan. to millions of sessions, so the bill that dominates is inference. That flips the calculus: a smaller model trained on far more tokens than Chinchilla-optimal can match a bigger one's quality while costing much less to serve per token.
- Objective
- Compute-optimal (Chinchilla)
- What you optimize
- Loss per training FLOP
- Tends to favor
- Balanced N and D
- Objective
- Deployment-optimal
- What you optimize
- Total cost incl. serving
- Tends to favor
- Smaller N, much larger D ('over-train')
- Objective
- Latency-critical (Cursor TabCursor's original autocomplete: multi-line, edit-aware suggestions you accept with the Tab key.)
- What you optimize
- Tokens/sec at quality bar
- Tends to favor
- Smaller, heavily distilled or over-trained model
| Objective | What you optimize | Tends to favor |
|---|---|---|
| Compute-optimal (Chinchilla) | Loss per training FLOP | Balanced N and D |
| Deployment-optimal | Total cost incl. serving | Smaller N, much larger D ('over-train') |
| Latency-critical (Cursor TabCursor's original autocomplete: multi-line, edit-aware suggestions you accept with the Tab key.) | Tokens/sec at quality bar | Smaller, heavily distilled or over-trained model |
The right scaling target depends on whether training FLOPs or lifetime serving FLOPs dominate the bill.
Show you know the limits of the law, not just the law. Say: "Chinchilla is compute-optimal for training, but for a product served at Cursor's volume I'd deliberately over-train a smaller model, because inference FLOPs over its lifetime swamp the one-time training cost. The scaling exponent still tells me how much quality I'm trading away." That nuance separates someone who read the paper from someone who ships.
Don't treat scaling laws as exact prophecy. They hold within a regime and a data distribution; data quality, repetition past a few epochs and architecture changes all bend the curve. The honest framing is that scaling laws are a planning tool with error bars, not a guarantee - and that data-limited settings (a finite pool of high-quality code) break the clean story.
Takeaway. Chinchilla says scale params and tokens together for a fixed budget (C ≈ 6ND), but for a product served at Cursor's volume you deliberately over-train a smaller model because lifetime inference cost - not training FLOPs - sets the bill.
Self-check
QYou have a fixed training-compute budget and your model will be served to millions of users for years. Why might you choose a model smaller than Chinchilla-optimal and train it on extra tokens?
Post-training pipeline end to end
After this you can lay out the stages from base model to shipped agent.
A state-of-the-art coding agent isn't one training run. It's a pipeline where each stage constrains the next and Cursor research owns decisions across all of them - including which base model to even start from.
Cursor has published that Composer 2Cursor's in-house agentic coding model: frontier-level coding quality at high speed and low cost, built as a software-engineering specialist rather than a general-purpose model. continued pretraining on a code-heavy mix before any preference work, which is a real, defensible choice you can speak to. Knowing the order of stages and what each one is good at, lets you reason about where a problem you're handed actually lives.
- 1Pretraining. Learn language and code from a broad corpus. Almost never something a single researcher reruns; it's the foundation everything else inherits.
- 2Continued / mid-training. Composer 2Cursor's in-house agentic coding model: frontier-level coding quality at high speed and low cost, built as a software-engineering specialist rather than a general-purpose model. continued pretraining on a code-heavy mix to shift the base distribution toward real software before any alignment. This is where the model's coding priors are set.
- 3SFT (supervised fine-tuning). Imitate curated demonstrations to install format, tool-call syntax and basic agent behavior. Cheap, stable, but capped by the quality of the demos.
- 4RL (reinforcement learning). Optimize toward a reward beyond what any demonstration showed - passing tests, good multi-file edits, graded quality. This is the core charter of the role.
- 5Deployment. Ship into real Cursor sessions, validate on real user data and feed signal (including online RL behind Tab) back into the next iteration.
Interactive diagram. Tab through its regions; each focused region shows its detail in the panel below.
Each stage constrains the next; RL is the optimization gate where reward, not imitation, takes over.
SFT vs RL: what each is actually forthe distinction interviewers test
Maximizes likelihood of curated outputs.
Installs format, tool syntax and a sane default policy.
Stable and cheap, but can't exceed its demonstrations.
Right tool for 'make it act like an agent at all.'
Maximizes expected reward, not imitation likelihood.
Can discover edits no demonstration contained.
Needs a reward signal (tests, graders) and is noisier.
Right tool for 'make the edit actually correct and good.'
Interactive diagram. Tab through its regions; each focused region shows its detail in the panel below.
The distinction interviewers test: shape versus score.
The crisp framing: SFT teaches the model how to respond in the right shape, RL teaches it to respond in a way that scores well. SFT is behavior cloning bounded by your demos; RL pushes past them toward whatever the reward rewards, which is also why a bad reward is dangerous.
Base-model selection as a research decisionComposer 2 chose Kimi K2.5
Cursor has stated Composer 2Cursor's in-house agentic coding model: frontier-level coding quality at high speed and low cost, built as a software-engineering specialist rather than a general-purpose model. was built on Kimi K2.5The open base model Cursor continued-trained into Composer 2 (1T parameters, 32B active, 256K context), chosen mainly for how well it fit Cursor's serving infrastructure., chosen on concrete internal criteria rather than a leaderboard number. That's the texture to bring: base selection is an experiment, not a vibe.
- Internal-codebase perplexity
- How well the base predicts Cursor's own real code, not a generic benchmark. A direct proxy for fit to the target distribution.
- Coding knowledge
- Breadth and depth of programming competence already baked in, so post-training builds on a strong prior rather than fixing fundamentals.
- State tracking
- Ability to follow program/agent state across many steps - the prerequisite for long-horizon agent-assisted editing.
Each criterion maps to a downstream need: distribution fit, prior competence and long-horizon coherence.
Kimi K2.5The open base model Cursor continued-trained into Composer 2 (1T parameters, 32B active, 256K context), chosen mainly for how well it fit Cursor's serving infrastructure. was also picked because its architecture fit Cursor's infrastructure. The shapes that matter at training and serving time - the MoE layout, the attention scheme, the native context window - were already close to what the ComposerCursor's own fast coding model, tuned for the editor and priced well below frontier models; the recommended day-to-day model for executing a plan. stack runs, so adopting it meant less infra surgery before the interesting work started.
- Spec
- Total parameters
- Value
- 1T
- Why it mattered to Cursor
- Large MoE capacity to learn from a broad code corpus
- Spec
- Active per token
- Value
- 32B
- Why it mattered to Cursor
- Only a fraction fires per token, so serving cost stays affordable
- Spec
- Layers
- Value
- 61
- Why it mattered to Cursor
- Depth for long-horizon state tracking across an agent session
- Spec
- Native context
- Value
- 256K
- Why it mattered to Cursor
- Long agent sessions fit without aggressive truncation
- Spec
- Attention
- Value
- Multi-head latent (MLA)
- Why it mattered to Cursor
- Compresses the KV cache, easing the inference-memory bottleneck
| Spec | Value | Why it mattered to Cursor |
|---|---|---|
| Total parameters | 1T | Large MoE capacity to learn from a broad code corpus |
| Active per token | 32B | Only a fraction fires per token, so serving cost stays affordable |
| Layers | 61 | Depth for long-horizon state tracking across an agent session |
| Native context | 256K | Long agent sessions fit without aggressive truncation |
| Attention | Multi-head latent (MLA) | Compresses the KV cache, easing the inference-memory bottleneck |
Kimi K2.5 base specs Cursor started Composer 2 from - chosen for infrastructure fit, not a leaderboard rank.
Picking the base is only the start. Cursor continued pretraining on top of K2.5 to raise its code-domain knowledge before any preference work, and the order of that continued run is itself a design choice.
- 1Short-context continued pretraining. Keep the context window modest at first and pour code-heavy data through it to lift the base's coding knowledge cheaply, before paying the cost of long sequences.
- 2Long-context extension to 256K. Extend the window out to the native 256K (RoPE base/NTK scaling territory) so the model holds a real repo, tool outputs and many turns of history in one session.
- 3SFT on agent-like data. Fine-tune on demonstrations shaped like real Cursor agent traces - tool calls, multi-file edits, test runs - so the model arrives at RL already behaving like an agent, not a chat model.
Cursor runs ONE harness across every model it serves - the same scaffolding for tool calls, context assembly and edit application, whether the model underneath is ComposerCursor's own fast coding model, tuned for the editor and priced well below frontier models; the recommended day-to-day model for executing a plan. or a third-party frontier model. Artificial Analysis found that other labs' models score best inside Cursor's harness, which is the striking part: "in some respects it is the product." The lesson for a research candidate is that model quality and harness quality are not separable - a gain you measure has to be attributed to one or the other, and the harness can lift any model you drop into it.
The mid-training data mix shapes everything RL can later reach. If continued pretraining over- or under-weights a language or a code style, RL inherits that bias and can amplify it. A senior answer treats the pipeline as coupled: a data choice three stages back can explain a reward-hacking pattern you see at the end.
When handed an ambiguous quality problem, locate it in the pipeline out loud: "Is this a base-distribution gap (mid-training), a behavior-format gap (SFT) or a reward-optimization gap (RL)?" Diagnosing the stage before proposing a fix shows the end-to-end ownership the role is built around.
Takeaway. The pipeline is pretrain → continued/mid-train → SFT → RL → ship, each stage constraining the next; SFT clones format and behavior, RL optimizes past the demos toward reward and base selection (Composer 2Cursor's in-house agentic coding model: frontier-level coding quality at high speed and low cost, built as a software-engineering specialist rather than a general-purpose model. on Kimi K2.5The open base model Cursor continued-trained into Composer 2 (1T parameters, 32B active, 256K context), chosen mainly for how well it fit Cursor's serving infrastructure., chosen for infrastructure fit) is itself a measured experiment - and Cursor's single harness is so much of the product that other labs' models score best inside it.
Self-check
QA model produces well-formatted, syntactically valid tool calls but the actual edits it makes are often wrong. Which stage is most likely the lever and why?
Efficient training systems
After this you can discuss the systems that make large-scale RL feasible.
Cursor frames its researchers as people who build the infra their experiments need, not just write loss functions. ComposerCursor's own fast coding model, tuned for the editor and priced well below frontier models; the recommended day-to-day model for executing a plan.'s training stack - MoE, custom low-precision kernels on Blackwell, async multi-region RL, sandboxed rollouts - is fair game in the interview.
You don't need to have written a CUDA kernel to pass, but systems literacy is part of the bar. You should know why MoE buys capacity, where low-precision risks numerical blow-ups and which parallelism axis bottlenecks an RL rollout-plus-train loop.
Mixture-of-Expertscapacity per FLOP
A dense model runs every parameter on every token. An MoE replaces the FFN with many expert MLPs and a router that sends each token to only a few of them. Cursor has described ComposerCursor's own fast coding model, tuned for the editor and priced well below frontier models; the recommended day-to-day model for executing a plan. as a large MoE with a small fraction of parameters active per token, so total capacity is huge while the FLOPs per token stay affordable.
Total params (capacity) decouple from FLOPs/token.
E.g. tens of billions active out of a much larger total.
More knowledge for a near-flat per-token cost.
Routing must spread load or some experts starve.
Expert parallelism means all-to-all comms across GPUs.
Auxiliary load-balancing loss to prevent collapse onto a few experts.
The classic MoE failure is router collapse: a few experts get all the traffic and the rest die, so you paid for capacity you can't use. The fix is a load-balancing auxiliary loss (and capacity factors). If you can name that failure mode unprompted, it signals you've actually thought about MoE rather than just heard the acronym.
Low-precision kernelsthroughput vs numerical stability
Cursor has said it wrote custom low-precision kernels to train MoE models on NVIDIA's Blackwell hardware. Lower precision (FP8 and below) roughly doubles throughput and halves memory traffic, but the numerics get sharp: small values underflow, large ones overflow and a single bad reduction can wreck a step.
- Precision
- BF16
- Use
- Default training compute; wide exponent range
- Risk
- More memory/compute than FP8
- Precision
- FP8
- Use
- Matmuls on Blackwell for ~2x throughput
- Risk
- Underflow/overflow; needs per-tensor or block scaling
- Precision
- FP32
- Use
- Master weights, optimizer state, key reductions
- Risk
- Slow/heavy; reserved for stability-critical paths
| Precision | Use | Risk |
|---|---|---|
| BF16 | Default training compute; wide exponent range | More memory/compute than FP8 |
| FP8 | Matmuls on Blackwell for ~2x throughput | Underflow/overflow; needs per-tensor or block scaling |
| FP32 | Master weights, optimizer state, key reductions | Slow/heavy; reserved for stability-critical paths |
Keep accumulation and master weights high-precision; push only the heavy matmuls to FP8 with scaling to stay numerically safe.
Parallelism and the RL loop bottleneckdata / tensor / pipeline / expert
- Data parallel
- Replicate the model, split the batch, all-reduce gradients. Simplest; bounded by gradient comms.
- Tensor parallel
- Split each matmul across GPUs. Heavy intra-layer comms; keep it inside a fast NVLink island.
- Pipeline parallel
- Split layers across GPUs in stages. Cheap comms but introduces bubbles you fight with micro-batching.
- Expert parallel
- Place MoE experts on different GPUs; tokens are routed there via all-to-all. The MoE-specific axis.
In RL the loop is generate rollouts, score them, then train on them - and the rollout (inference) phase often dominates wall-clock, because generation is sequential and the policy keeps changing. The async trick is to decouple actors from learners: rollout fleets generate against a slightly stale policy while learners update, instead of letting expensive GPUs idle between phases.
Actors and learners run on separate fleets and don't block each other.
Off-policy correction handles the lag between the rollout policy and the current policy.
Multi-region spreads the sandbox/GPU fleet to where capacity is.
Each coding episode runs in an isolated sandbox that can execute code and tests safely.
Must be fast to spin up and reproducible, since rollout throughput gates training.
Realistic Cursor sessions, not toy tasks, so reward reflects real edits.
When asked to speed up an RL run, profile the loop first and say so: "In agent-assisted RL the rollout phase usually dominates, so I'd measure the generate-vs-train split before touching kernels. If rollouts dominate, async actors and faster sandbox spin-up beat a tensor-parallel tweak." Profiling before optimizing is the truth-seeking habit they screen for.
Takeaway. MoE buys capacity per FLOP (watch router collapse - fix with a load-balancing loss), FP8 on Blackwell doubles throughput if you keep accumulation high-precision and large-scale RL stays feasible by decoupling async rollout actors from learners so expensive GPUs never idle.
Self-check
QIn an MoE model, why is a load-balancing auxiliary loss usually necessary?
Experimental design and rigor
After this you can design experiments that yield trustworthy conclusions.
Cursor screens hard for truth-seeking: caring more about what's true than about being right. Experimental rigor is where that trait becomes operational and it's the easiest place to lose a research deep-dive if your conclusions don't hold up under questioning.
The deep-dive round is you presenting prior work and defending the decisions under pressure. The paid practical onsite is you running a real experiment and reasoning about noisy metrics live. Both reward the same habits: isolate variables, quantify uncertainty and predeclare what would prove you wrong.
Isolate one variableno confounds
The most common self-inflicted wound is changing the method and the data and the eval at once, then crediting the win to the method. If two things move together, you've learned nothing about either. Change one thing, hold a matched baseline fixed and keep the eval identical across arms.
- Run a matched baseline under the exact same data, eval and compute - not last quarter's number from a different setup.
- Change exactly one factor per comparison; if you must change two, run the 2x2 so you can attribute the effect.
- Freeze the eval set and harness across arms; an eval that drifts between runs invalidates the comparison.
Quantify uncertaintyone run is not a result
RL training is high-variance: seed, data shuffle and rollout sampling can swing a SWE-bench-style number by more than the effect you're chasing. A single lucky run is a story, not a finding. Report across seeds with a spread and ask whether your claimed delta clears the noise floor.
- Multiple seeds
- Repeat the key comparison across several seeds and report mean and spread, not a single point.
- Noise floor first
- Estimate run-to-run variance under no change, so you know how big a delta has to be to mean anything.
- Eval variance
- Small or contaminated eval sets are noisy on their own. Account for benchmark variance, not just training seed variance.
Beware metrics that move for the wrong reason. A SWE-bench jump can come from train/eval contamination, a grader the model learned to game or a harness that silently caught more partial credit. Reward hacking looks exactly like progress on the dashboard. Before you celebrate, ask what else could produce this number and go check.
Leakage and reward hackingthe two ways a coding eval lies
- Failure
- Train/eval contamination
- What it looks like
- Suspiciously high eval; gains don't transfer to live sessions
- How you catch it
- Dedup by repo/problem; hold out truly unseen tasks; check overlap
- Failure
- Reward hacking
- What it looks like
- Reward climbs, real quality doesn't
- How you catch it
- Inspect winning trajectories by hand; audit the grader on adversarial cases
- Failure
- Wrong-reason metric
- What it looks like
- A number moves with no plausible mechanism
- How you catch it
- Trace the cause; reproduce the delta on a controlled slice
| Failure | What it looks like | How you catch it |
|---|---|---|
| Train/eval contamination | Suspiciously high eval; gains don't transfer to live sessions | Dedup by repo/problem; hold out truly unseen tasks; check overlap |
| Reward hacking | Reward climbs, real quality doesn't | Inspect winning trajectories by hand; audit the grader on adversarial cases |
| Wrong-reason metric | A number moves with no plausible mechanism | Trace the cause; reproduce the delta on a controlled slice |
Offline eval can rise while shipped impact flatlines - always close the loop against real Cursor usage.
Predeclare the kill criteriontruth-seeking, made concrete
Before the run, write down the result that would make you abandon the idea. Deciding the bar in advance defends you against moving the goalposts when you're emotionally invested, which is the whole point of truth-seeking as a discipline rather than a slogan.
- 1State the hypothesis. A specific, falsifiable claim: 'grader G raises live edit-accept rate by >=2pts over the baseline.'
- 2Define the kill criterion. The result that ends the idea: 'if the seed-averaged delta is under 1pt or live impact is flat, I stop.'
- 3Pre-register the eval. Fix the eval set, seeds and metric before looking, so you can't retrofit a win.
- 4Run, then report honestly. Show the spread, name confounds you couldn't rule out and state what you'd do next - including killing it.
"Before running, I wrote the kill criterion: under a 1-point seed-averaged gain or no movement on live accept-rate, I'd drop it. The offline number came in at +1.4 but live was flat, so I traced it - turned out the grader was rewarding longer diffs, not better ones. I killed that grader and reported the negative result."
Volunteer a result you killed. Describing an experiment you abandoned because the data said so, calmly and without spin, is the single most credible demonstration of truth-seeking you can give. Cursor would rather hire someone who killed their own pet idea than someone who's never reported a negative result.
Takeaway. Isolate one variable against a matched baseline, prove your delta clears the seed-and-eval noise floor, treat a metric that moves for no clear reason as possible leakage or reward hacking and predeclare the kill criterion so truth-seeking is a rule, not a mood.
Self-check
QYour new grader raises an offline coding benchmark by 2 points, but live edit-accept rate in real Cursor sessions doesn't budge. What are the leading explanations and what do you do?