Making LLM-as-Judge Scoring Reproducible and Trustworthy A developer built evalgate, an eval tool whose llm-judge scorer makes LLM-as-judge grading reproducible by combining a caller-supplied fixed rubric, a pinned JSON output contract, temperature 0, a deterministic mock judge for unit tests, and a guard against judge drift. The approach treats unparseable judge replies as scored zero events with a diagnostic reason rather than crashes, and the mock provider computes scores from word overlap against the reference and criteria without any network call. I love using a language model to grade another model's output. A judge model can score "is this support reply empathetic and correct?" in a way that a regex never will. But the first time I wired one into CI, my test suite started flaking: the same input scored 0.8 one run and 0.55 the next, and a green build turned red for no reason I could point to. An eval you cannot trust to give the same answer twice is not a gate. It is a coin flip with extra latency. This is a tutorial on making LLM-as-judge scoring reproducible. I will ground it in the llm-judge scorer from my eval tool, evalgate, but the techniques carry to any stack. There are five moves: a fixed rubric, structured output, temperature 0, a deterministic mock judge for tests, and a guard against judge drift. The single biggest source of noise is a vague ask. "Is this a good answer?" invites the judge to invent fresh criteria every call. Instead, pass the exact rubric and pin the response shape. Here is how evalgate builds the judge prompt: export function buildJudgePrompt criteria: string, output: string, expected?: string : string { return "You are a strict evaluator. Score how well the RESPONSE satisfies the CRITERIA.", expected ? REFERENCE an ideal answer :\n${expected} : "", CRITERIA:\n${criteria} , RESPONSE:\n${output} , 'Reply with ONLY compact JSON: {"score":