Score decisions on the public Jevals sets, with the boards' own formulas - #272
Merged
Merged
Conversation
The decision bench could only score AINode's own 110-item set, so an AINode-served model had no number anybody outside this repo could read. This adds the independent recipe as a second measurement under the same subcommand: the public question sets the Jevals boards use, their formulas, five repeats per question, and two transports so the same run can target /v1/decide or any server speaking the Jev /v1/systemone wire format. The recipe is recorded in bench/decide/JEVALS.md against the pages it came from and the date they were read, with every deviation named. Four manifests carry the sets without any item text; `decide download` fetches the text and verifies every state against its published hash, which is also how the three Jevals state constructions were recovered (Banking77's state key is `message`, not `text`, and PubMedQA's is `context` holding the list). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
webdevtodayjason
force-pushed
the
fable/decide-bench
branch
from
September 22, 2026 01:31
9b6c79e to
475f42a
Compare
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.
The decision bench could only score AINode's own 110-item set, so an AINode-served model had no number anybody outside this repo could read. This adds the independent recipe the public boards use as a second measurement under the same
decidesubcommand, on the same public question sets, with the same formulas, so an AINode row can sit next to Jev and its clones.The recipe is recorded in
bench/decide/JEVALS.mdagainst the pages it came from and the date they were read, with every deviation named. That file, not this PR body, is authoritative for what a number here means.The recipe as implemented
Read from https://jevals.com/methodology (suite 0.1.0) and https://jevals.com/policy/ on 2026-09-21, plus https://github.com/fstandhartinger/jevbench's README (JevBench v1.2.10, the maintained multi-system board) and the
LocalLLaMA/typed-decisionsdataset card the same day.100 * (1 - L / L_prior). 100 perfect, 0 no better than answering with the label base rates, negative shown and never clamped.Lis the mean per-item loss, itself the mean over that item's repeats: the multiclass Briersum_k (p_k - y_k)^2forchoiceandnoul, the ranked probability score over cumulative levelssum_{k<K}(P_k - Y_k)^2/(K-1)forscore.L_prioris the same loss for the label prior on the same items.prior_accuracyand again as JevBench'smajority_class_accuracy.min(9, floor(round(100*c)/10))(JavaScript rounding, soround_half_up, not Python's tie-to-even), with the full reliability table kept in the record so a model card can draw the calibration curve.choice0.96,noul0.91,scorenone) with this run's coverage and accuracy at them, plus agate_localcomputed by the same rule over this one run and labelled as not a board number.--repeats), one question per request, choice options presented in a seeded order that repeats 0 and 1 share and repeats 2, 3 and 4 each get their own; score levels and yes/no never reordered.pick_flip_rate(share of questions whose pick changed at least once across the repeats) andconfidence_swing(the largest spread one question's confidence showed, with the question named), beside the board's ownrepeat_flip_rate(repeats 0 and 1) andorder_flip_rate(the four option orders).schema_validityandschema_validity_strictunder its 2 percent and 0.001 sum tolerances. A yes/no answer of exactly 0.5 has no pick and counts as wrong. A transport failure is never scored.usd_per_1k_decisionsbeside the total, with JevBench'scost_basissaying which it is, so a $0 is not read as free.The sets
Committed as manifests under
bench/decide/sets/, with no item text. The three Jevals suite files are verbatim fromhttps://jevals.com/data/suites/0.1.0/<id>.json(CC-BY-4.0).pubmedqanoulqiaojin/PubMedQApqa_labeled/train@9001f285banking77choice, K=77mteb/banking77default/test@18072d26helpsteer2score, K=5nvidia/HelpSteer2default/validation@990b2711typed-decisionsLocalLLaMA/typed-decisionsall/test@ea930645decide downloadfetches the item text into the gitignoredbench/decide/cache/and verifies every state against the manifest'sstate_sha256before writing. All 900 Jevals hashes reproduce, which is what makes a number here comparable to a board number, and it is how the state construction was recovered in the first place: Banking77's state key ismessage, not the upstream field nametext, and PubMedQA's iscontextholding the list of passages, notcontext.contexts. Neither is published. One trap worth the line:mteb/banking77ships both atest.jsonl(3,080 lines) and the parquet behinddefault/test(3,076 rows), and the suite'srow_idxis the parquet index, so loading from the jsonl puts 258 of the 300 states on the wrong row. The hash check catches it.typed-decisionsis the fourth set because it is the one public set already in the/v1/systemonerequest shape, with a train/test split and gold distributions; its hashes are ours, computed at the pinned revision, and the manifest says so.Deviations from jevals.com, called out
/v1/decideis logprob-based, which suite 0.1.0 excludes. It constrains the engine to one option label and reads the distribution off the first token's logprobs. Jevals states logprob rows are not in that version and its LLM rows are verbalized; JevBench states it uses token-level logprobs for nobody. Every record carriesprobability_sourceoflogprob,nativeorverbalizedin JevBench's own vocabulary, because a row is only comparable to a row that got its probabilities the same way. Thesystemonetransport isnative./v1/decideletters its options, and past 26 a two-letter label can share its mass with a one-letter one (the limitation already documented inainode/api/decide.py). Banking77 has 77 options, so its Decision Score through that transport reads as a floor, not a point. The run's notes say so.{options_heading},{options}and{what}unfilled and the hash is over the filled version, so it cannot be reconstructed. Both transports here take a typed question natively, so there is no prompt of theirs to match.scoreresponse shape for/v1/systemoneis authored: jevals.com documents the primitive but not the field a Jev-format server answers it in, so the parser acceptsscore,levelorchoiceand a response matching none is one malformed row.vs_goldis ours.soft_accuracy,total_variation,klandbrier_vs_goldon the one set with gold distributions are AINode's definitions, stated in the block, because the card prints columns of those names without publishing the arithmetic.Contamination, in the record
banking77is in Kev's published training data (thekev-9bmodel card front matter listslegacy-datasets/banking77underdatasets:) and in Laya's training mix;pubmedqasits inside decider's development loop. Each finding travels with its evidence and its primary source URL insets.CONTAMINATION, in the record and in the run's notes. A row for one of those systems on that set measures memorisation. It says nothing about an AINode-served model that did not train on them.One real bug found and fixed while building this
Pooling a mixed set's questions into one label prior is wrong:
typed-decisionsasksactionwith four options in one workflow and five in another, and a single pooled prior is a baseline over an answer space neither question has. The prior scored -297 on the choice board before the fix. A set is now broken down by answer space (one(type, options)pair, named<workflow>/<question>) with a per-primitive roll-up, andtests/test_bench_decide_jevals.pypins that the label prior scores exactly 0 on all four committed sets and every one of their spaces.No answer key ever reaches the model
Labels live in a question file's separate
labelsmap, never inside a question. A question carrying anything answer-key-shaped is a load error, and the assembled request body is checked again before it is sent: a leak refuses the request rather than producing a very good score. A gold distribution is allowed in a file and never on the wire. The round-trip tests assert that every body a fake endpoint received was clean.Commands
Which key goes where is decided by the endpoint's HOST, not by a flag.
api.typesafe.airesolves TypeSafe's credential; anything else resolves the node's. No ordering of flags can post a fleet key to a vendor. Nothing is ever printed but the source it came from.What was run, and what was not
Only a 10-question transport smoke against
spark-1-dgx:3443/v1/decidewith the fleet key, to prove the wire: 10 of 10 answered, accuracy 0.800 against a floor of 0.800, Decision Score 7.8, ECE 19.5 points, coverage 0.60 at the published 0.91 gate, p50 1420 ms, no malformed answers, no key in the record. That record is deliberately not committed: a 10-question single-repeat run is a transport proof, not a suite result, and it has no business in the published table. No full set was run from this worker.The README's "Decision runs" table gains Decision Score and Hand-off at 95%, and its ECE cell now carries its unit (
5.8 ptfor the ten-bin recipe figure,0.059for the legacy five-bin ratio) so two definitions never share a column silently. The two existing legacy rows read "not measured" in the new columns, which is the truth: they did not take those measurements.Changelog text for the release PR
Added
ainode-bench decide --suite all --transport decide|systemoneruns PubMedQA (noul, 300), Banking77 (choice, 300, K=77), HelpSteer2 helpfulness (score, 300) andLocalLLaMA/typed-decisions(mixed, 2000 decisions over 400 cases) at 5 repeats per question, against either AINode's ownPOST /v1/decideor any endpoint speaking the JevPOST /v1/systemonewire format. Per set it reports the Decision Score against the label prior (100 perfect, 0 the base rates, negative worse), accuracy with its guessing floor, the calibration gap in points over ten bins with the reliability table behind it, the hand-off share at 95 percent, the published gate with this run's coverage, pick flips and confidence swing across the repeats, p50 and p95 latency, questions per second, malformed answers, and cost when a price is given.--questions <file>scores any question file in the same shape, so a private blind set never has to be committed. The recipe, the date each source page was read and every deviation from it are inbench/decide/JEVALS.md; the sets arebench/decide/sets/andainode-bench decide downloadfetches the item text, which is not committed, and verifies every state against its published hash.🤖 Generated with Claude Code