Repository navigation
Spec: blind pairwise grading of process Trials by a Grader panel and people - #1944
Merged
Merged
Conversation
…#1883) The proxy's OpenCode provider hosts gain Baseten's inference.baseten.co beside Fireworks' api.fireworks.ai. The Credentials take an [opencode.keys] table of keys by OpenCode provider name, with opencode.api_key kept for any provider without its own, so two OpenCode seats on different providers each get their own key.
After both Arms' Trials of a pair finish, run each Arm's new test files on the unchanged base and against the other Arm's final commit, offline in the code-Grader sandbox under the Bar's timeout, reusing the process Grader's export and overlay. A task opts in with process_grading.new_tests (patterns and a per-file command). Results are kept per pair as evidence, never Scores, and shown as the Experiment's pairs (result format 9), in the text view and on the Console page. Closes #1881
Work out the OpenCode Trial's provider once, keep vocabulary to the glossary's, list the OpenCode keys in the Credentials entry and module doc, and rewrap long lines.
A timed-out run or an unpreparable snapshot no longer reads as new tests failing on the base or as a cross-test disagreement: the code Grader now says whether each check ran to an exit status, and such runs leave the result null. Document per-field null rules, show unfinished runs in the text view and Console, and share the HEAD lookup and attempt discovery.
Allow Fireworks and Baseten through OpenCode, with a key per provider
Run base-tests and cross-tests for each pair of Trials
…dict The Bar can name a Grader panel: --panel-seat harness=..,model=..[,effort=..] seats, several per family, a vote unit (--panel-vote family|model, family by default) and the arm-family rule (--panel-arm-family-rule on|off, on by default). Each seat reads every finished pair of process Trials in a fresh sandboxed session per presentation order. The blind packet holds the Ticket, the criteria, a fixed rubric, and per side the outcome, the diff against the base and the Pair evidence, with A and B shuffled per pair and swapped in the second order. Validated calls are saved by Arm, so a resume asks only for missing ones. A Grader's call that flips with the order is a tie. Seats from either Arm's family are reported but don't vote while another family sits. Each family takes its own majority first, or each Model votes; a call needs more than half the votes, and a tied merge call is not ready. Every seat's calls and the panel's result are reported under panel (result format 10) and in the text view, beside the unchanged Verdict. Closes #1882
Each pair with evidence gets a blind page and a CLI twin: the Ticket, its numbered acceptance checklist, both changes side by side with code before tests, and their evidence, on sides drawn per pair from the Bar's seed. A reader seals a merge call per side before a preference and optional rubric; records are append-only and attributed. Arm identity and the panel's calls are revealed after the preference. People's calls and people-panel agreement show beside the Verdict (result format 10).
Seal a reader's merge calls until their preference, and mark a review begun after the reader's reveal as not blind, keeping it out of people-panel agreement. Document the --pair JSON and review records and check them, with people's calls and panel calls, against the result contract. Share the preference values, next-step command, reveal line and changed-path listing; read the Ticket input by its shared name and require a file. Describe the blind page on the workflow page and read its format number from the contract.
Remove identifying added lines from panel packet diffs, as reports already are, and read diffs within the Bar's timeout. Share one private Grader session between the model Grader and the panel. Decode the preference as an enum, name ballots, seat calls and the Arm shown as A plainly, key per-Model votes by Model, call the sides Trials in the prompt, and grade with the panel after the model Grader.
Add the blind pairwise review page to the Console
Keep the Grader panel beside #1885's blind pairwise page: the panel's result fills each Pair's panel calls, for the page's reveal and people–panel agreement, and its contract shares ArmPreference.
Grade each pair of process Trials with a Grader panel, beside the Verdict
The pre-Experiment estimate lists each panel seat's remaining sessions and expected cost from the frozen price table. Panel spend is reported apart from the Arms under panel_spend, and --panel-spending-limit pauses grading once a run's panel sessions reach it; a resume continues from saved calls.
…eral readers (#1886) The Bar now sets the Grader panel and the people each off, beside or counted, as ADR 0028 describes. Named readers get queues drawn by pair from the Bar's seed with a set overlap, and a shared pair is ready only if every reader calls it ready. Counted calls make a Trial pass only when its code Grader passes and its pair is called ready; a people-only sample decides on the sampled pairs alone; with both counted the panel stands in on unread pairs, guarded by a voting-family check at start and a people–panel agreement level. The Verdict waits on people while a reader has pairs to call, and people–people agreement is reported.
Release Trial repositories when a people's call settles the Verdict, through one shared publish step for rechecks, leak decisions and counted people's calls. Name the Verdict's sample agreement and the Bar's PeopleSetting apart from the reported people, and count pairs, not Eval tasks, in a Verdict on the people's sample alone.
Save a panel call before pricing its session, so an unpriceable session under a spending limit pauses without being graded again on resume. Ask about the panel alone when only its calls remain. Name the estimate's types, move a seat's measured mean onto SeatSpend, share the positive amount parser and the plural helper.
Estimate and cap the Grader panel's spend (#1884)
# Conflicts: # docs/experiment-results.md # docs/guide.md # site/architecture/index.html # site/docs/index.html # site/how-it-works/index.html # site/index.html # src/console/start/experiment.rs # src/evals/experiment/options.rs # src/evals/experiment/panel.rs # src/evals/experiment/panel/tests.rs # tests/experiments/panel.rs
Count the panel or people in the Verdict, with seeded samples for several readers
- Limit a sample-only Verdict's per-pair unit to suites of process Eval tasks. - Blind the pair page's diffs and evidence errors as the panel's packets are. - Choose the single model Grader by the panel's family rule, not exact Model names. - Read the panel's Ticket through the pair page's guarded reader. - Say the panel counts in the Verdict when the Bar counts it; seat Kimi through its own Harness in the guide's panel examples.
JacobStephens2
marked this pull request as ready for review
November 10, 2026 16:55
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Blind pairwise grading of each Baseline–Candidate pair of process Trials (Baseline Trial k with Candidate Trial k), by a Grader panel, by people, or both. The Bar fixes who decides before the first Trial (ADR 0028).
How the Verdict is decided for each pair:
--panel-seat harness=…,model=…[,effort=…],--panel-vote family|model,--panel-arm-family-rule on|off,--panel off|beside|counted,--panel-families,--panel-agreement,--panel-spending-limit,--people off|beside|counted,--people-reader,--people-sampleand--people-overlap. The Console's start options take the same flags.api.fireworks.aiandinference.baseten.co.[opencode.keys], falling back toapi_key.pairs,panel,panel_spend,people,bar.panel,bar.people,deciders,PairPageand thewaiting_on_peoplestate.docs/experiment-results.md,docs/eval-tasks.md,docs/trial.md, the glossary, code navigation, the Panel Grader prompt and the three hand-written site pages.This review's fixes (
760fcbba)The review also fixed two pieces of text.
panel.rsanddocs/experiment-results.mdno longer say the panel is "never in" the Verdict. The guide's panel examples now seat Kimi through the Kimi Code Harness rather than OpenCode, as the Spec's Q6.4 says.Evidence
Execution evidence
All three behaviour fixes started from the reviewer's failing test.
Spec P4: a sample-only Verdict resets every suite's statistics.
cargo test --bin thirdshift deciders::tests::a_sample_only_verdict_leaves_other_suites_statistics_alonetest result: ok. 10 passed; 0 failed(all ofdeciders::tests).Spec P1: the blind page shows identifying lines and error text.
cargo test --test console pairwise::identifying_lines_and_paths_stay_off_the_blind_pagetests/console/pairwise.rs:613. The page containedopus-fixtureandunavailable: other Arm: Eval git failed: fatal: /h/trials/abc--baseline--0/attempt-1/repository.cargo test --test console pairwise→test result: ok. 8 passed; 0 failed.Spec P6: the single model Grader excludes by exact Model name.
cargo test --test experiments model_graders::the_model_grader_comes_from_another_family_than_either_armcargo test --test experiments model_graders→test result: ok. 14 passed; 0 failed.Final validation:
scripts/affected-tests refs/remotes/origin/main.npm test --prefix site,cargo build --lockedandnpm test --prefix console.cargo testhad two failures, both intests/process.rsfindings::*, which this branch doesn't touch. They failed under the full run's load. Re-run alone,cargo test --test process findings::→test result: ok. 18 passed; 0 failed.cargo test --bin thirdshift prompts_page→ 14 passed.npm run docs:check --prefix site→ exit 0.Visual evidence
These captures were published by the Ticket PRs and are reused here. This review's fixes change only which diff lines and error text the blind page prints, not its layout.
Blind pair page, 1440×900, before any call (#1885). Before: the route doesn't exist.
Blind pair page, 390×844 (#1885).
Experiment page, People's calls with counted readers' queues, 1440×900 (#1886).
The Pair evidence table (#1881) has no published capture: that session couldn't upload one.
Seams under test
thirdshift experiment candidate --jsonthrough the Experiment fixture, with fake Harness scripts as panel Graders (tests/experiments/{pairs,panel,model_graders}.rs).tests/console/{pairwise,experiments}.rs).deciders::decidewithgrading::assess, for Verdicts under each Bar setting (src/evals/experiment/deciders/tests.rs).Review coverage
Reviewed with
thirdshift-code-reviewagainstrefs/remotes/origin/main. Standards raised 12 findings and Spec raised 11. Every changed file was read by both axes, apart from generated output:prompts/panel-grader.mdis excluded from both axes. Its source issrc/prompt.rs, andcargo test --bin thirdshift prompts_pagepasses.site/docs/index.htmlis excluded from both axes. Its source isdocs/guide.md, andnpm run docs:check --prefix sitepasses.Unaddressed findings
Standards
Credentials::read_fromispub(crate)for a test. Declined, as on Allow Fireworks and Baseten through OpenCode, with a key per provider #1942: the sandbox tests buildOpenCodeKeysthrough the real Credentials parser (src/sandbox.rs:1993), not through a constructor that bypasses it.tests/experiments/pairs.rsnames what the 4s covers. No change.Calltypes, twoPreferencetypes and two rubrics (Mysterious Name). The rubric and result shapes are open in Align the people's blind-page rubric and panel result shape with the Grader panel (#1882) #1947. Renaming before that decision would churn the same types twice.panel::remainingmust count unfinished pairs before any Trial, whilepanel::runskips them (src/evals/experiment/panel.rs,remaining/run).git diffargument vector. The two call sites differ in purpose.pairs::diffsplits the diff per file and keeps it;panel::Sides::readblinds the whole patch. The Ticket-read part of S6 is fixed.decided.callsmatch ingrading::evaluate. Declined, as on Count the panel or people in the Verdict, with seeded samples for several readers #1953: onlyevaluateknowsdropped_as_void(src/evals/experiment/grading.rs,evaluate).WaitingOnPeopleedits across five files. This follows the existingWaitingOnLeakspattern (src/console/peek.rs,src/logs/reading/inbox.rs). Gathering them is a refactor outside this Spec.src/resend_key.rsowns OpenCode keys. That file is the Credentials module, which already holds every provider's key. Its name predates this Spec.pairwise. These are judgement calls.pairwise::root()follows the six existing copies of the Experiments root, and gathering them all is outside this Spec.Spec
a_readers_queue_is_not_shown_beside_arm_attributed_evidencefailed as described: the page contains<td>Baseline</td><td><code>tests/left_test.py</code></td>. Moving the queue alone doesn't close the leak, because the Experiment page shows Arms, Trials and Scores to every reader. Whether to hide that evidence while a reader has pairs to read, to add a per-reader queue page, or to accept that the Experiment page isn't blind is for the Spec and the Day shift to decide → Keep a reader's queue of blind pairs away from Arm-attributed pair evidence #1956.readers_fill_in_the_panels_rubricfailed (["correctness", "tests", "scope"]against["criteria", "tests", "scope", "code"]). This is already open as a Spec decision → Align the people's blind-page rubric and panel result shape with the Grader panel (#1882) #1947.kimi_is_one_family_whichever_harness_runs_itfailed (left: "fireworks-ai",right: "moonshot"). That matches Spec: blind pairwise grading of process Trials by a Grader panel and people #1872's "Model families come from each seat's provider". Whether family should mean the Model's maker is open → Decide whether a Grader panel seat's family is its host or its Model's maker #1949.deciders::decide+grading::assessseam (src/evals/experiment/deciders/tests.rs). Counted people is tested end to end through the Experiment fixture (tests/experiments/panel.rs), which exercises the same plumbing.waiting_on_peopleas scope creep. Declined, as on Count the panel or people in the Verdict, with seeded samples for several readers #1953. People's calls arrive after the run, so a counted Verdict must wait for them, aswaiting_on_leakswaits for leak decisions (src/evals/experiment/store.rs,refresh_verdict).Security review outcome
No unaddressed introduced findings.
Merge Danger
Door: two-way
Everything is opt-in through the Bar. Without
--panel-seator people flags, an Experiment runs as before, apart from base-tests and cross-tests for tasks that nameprocess_grading.new_tests. The model Grader's choice is the exception: an Experiment can now pick a different Grader Model, when a configured Model shares a family with an Arm. Result format 10 is additive.Blast Radius: Experiments
Consumers of Experiment JSON see format 10. The Console gains the pair page and the Experiment page gains its People's calls and Pair evidence sections. The sandbox proxy allows two more provider hosts, for OpenCode sessions only.
Closes #1872
Tickets
Built with claude 2.1.314 · opus · default effort