Converge eval rubric schema with Magister's eval runner (3-layer rubrics, brand fixtures, config-as-candidate)

Author: coreyhaines31Created Jul 23, 2026Updated Jul 23, 2026
Labelsenhancement

Why

Elliot built a marketing eval runner inside Magister (magister-marketing PR #890, branch codex/model-marketing-evals) — evals/ with candidates, brand fixtures, per-family rubrics, a runner engine, deterministic + blinded grading, and evidence capture. It's the same primitive as our open evals/ framework (#479). His README explicitly documents "the boundary for extracting the generic runner into a future standalone or open-source package."

These are the two halves of one thing: his is the proprietary, prod-integrated engine (real brand fixtures, canary safety, model routing); ours is the open, credibility layer (public rubrics + published human-agreement numbers). They should share a rubric/judge schema so a judge authored in one runs in the other. This issue tracks converging the two.

Already incorporated (done, not this issue)

Quick wins from Elliot's runner already merged into our framework (feature/eval-framework-phase0):

  • Judge pinned to temperature: 0 (deterministic grading; kills the sampling-noise phantom swings from Magister #819, where a near-identical answer scored 71 then 49).
  • Injection defense — graded items framed as untrusted data, not instructions.
  • Evidence capture — each benchmark run writes immutable benchmark/runs/<id>/run.json for offline inspection/re-grade.
  • METHODOLOGY "Deterministic judging" section, credited to Magister.

The convergence work (this issue)

1. Three-layer rubric schema (the big one)

Elliot's rubrics separate three concerns; ours are single-layer LLM PASS/FAIL. Adopt his split so a rubric is a superset both runners understand:

  • hard_gates — absolute fails (all claims grounded in the fixture, no forbidden claims, draft-only). Any gate fail = FAIL regardless.
  • programmatic_checksdeterministic code checks, no LLM: labeled_character_limit (Meta primary text ≤125, headline ≤40), minimum_heading_matches (≥3 angles), etc. Un-gameable, free, noise-free.
  • subjective_dimensions — 1–5 LLM scales (positioning, angle diversity, channel fit, testability), each with an explicit description/anchor.

Needs: a shared JSON schema (schema_version, id, task_family, the three arrays), a deterministic check runner in our harness, and a way to map 3-layer scores → an overall verdict for the calibration loop. Migrate our 8 judges to the new schema.

2. Brand-fixture grounding

Replace/augment our one-line benchmark briefs with synthetic brand fixtures (Elliot's fixtures/brands/<brand>/): product-marketing.md + sources/product-facts.md + constraints.json (authoritative_sources, forbidden_claims, required_disclosure, allowed_side_effects). This is what powers the "grounded claims / no forbidden claims" hard gate — it catches hallucinated marketing claims, which our current benchmark can't see. Add untrusted-notes.md-style fixtures for a prompt-injection resistance eval dimension.

3. Config-as-candidate + reproducibility

Extend our pricing.json registry from {model, price} to Elliot's candidate shape: model + effort + verbosity + max_output_tokens + cost_ceiling_usd_per_attempt + temperature_policy (he pins temperature_policy: "omit" in v1; GPT declares verbosity, Claude uses null). Add experiment-level random_seed + budget caps (max cost / attempts / deadline).

4. Blinding + evidence formalism

He formalizes blinding: the judge gets pairs.jsonl only; candidate identities join after a schema-valid import via a separate pair-map.json. Generation and grading are fully separate — evidence written once, then deterministic checks + blinded reviews + reports rerun offline. Align our benchmark's evidence format so a run is regradable and identity-blinded.

5. Honest-reporting metadata

Stamp rubric_version on every score; mark partial runs / unscored counts; never blend incomparable source sets into one trend (Magister #819's lessons).

Coordination

  • Sync with Elliot on the shared rubric schema before either side hardens its format — a divergent schema defeats the purpose. His PR #890 is the reference implementation; our #479 is the open target.
  • Decide the extraction boundary: does our open evals/ framework become the generic package his README references, or do both depend on a shared schema/spec repo?

Dependencies

  • Our framework is on feature/eval-framework-phase0 (awaiting Corey's labeling pass before merge). The schema migration should land before or with that so we don't re-author judges twice.
  • Elliot's #890 (open). Coordinate merge order / schema freeze.

Filed from a review of Elliot's Magister eval runner. Companion to #479 (framework) and #480 (model benchmark).

Source: coreyhaines31/marketingskills