Repository navigation
feat(vieval,ui)!: replace exact and judge scores with named, declared scores - #34
Merged
Merged
Conversation
Copy the create-pr skill of moeru-ai/auv and replace its AUV surfaces (Rust APIs, Protobuf / Runner) with the surfaces vieval exposes: the CLI, the eval DSL and package exports, and the report files and viewer HTTP API. Co-Authored-By: Claude Opus 5.5 <[email protected]>
… scores
A run page showed `hybrid = (exact + judge) / 2`: a number without a name that
averaged two different questions, while other pages showed `exact`. A third
quantity such as latency had no slot, and benchmarks with several named
rewards could not be imported.
Scores now have names and definitions:
- `defineScore(name, { label, description, primary, combine, errors, grader })`,
with localized labels like `defineMetric`
- `recordScore(score, value, { rationale, grader, metadata })` and
`recordUnscored(score, reason)` for values a grader could not produce
- derived scores (`combine: all | mean | weighted`, `all` with `atLeast`
thresholds) computed when a case try settles
- `describeTask(..., { scores })` announces scores before the first case
- one state rule (`scoreCases`) for the task, reports, CLI, and viewer; the
completion rate counts each case once by its final outcome
- the headline (`resolveHeadline`) is written into `run-summary.json`
Event schema v3 (`score.defined`, `score.recorded { name, value | unscored }`),
`run-summary.json` v2, and `cases.jsonl` v2. Older reports are rejected and
listed as unsupported in the viewer. `exact`, `judge`, `hybrid`, `strictExact`,
`scoreKind`, and `toRunScores` are removed.
The viewer shows the primary score with its label and the completion rate
everywhere, a Scores table with formulas, graders, and unscored reasons, score
badges with rationale on the case page, scores in the metric panels, and a
warning when compared columns were graded differently.
BREAKING CHANGE: `recordScore(value, kind)` is now `recordScore(score, value)`;
`TaskRunOutput.scores` holds `ScoreSummary` objects; reports written by older
versions are not read.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A case that errored in its first auto attempt and passed in a later one was counted as errored, listed as a failure, and offered for resume. The project summary kept only the first `case.ended` of each case. It now keeps the last `case.ended` of each case and only its failure, which also matches the completion rate. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Approval required for deploying to Cloudflare Workers (Preview) for docs.
|
The per-case scoring rule lived in three places: inside `scoreCases`, again in `report-records.ts` (with a NOTICE to keep both in step), and through a one-case `scoreCases` call in the viewer. `countCase` in `core/scoring` now owns it, and `scoreCases`, `cases.jsonl` records, and the viewer's per-case values all call it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
`vieval/core/processors/results` (`processRunResults` with its threshold and max-failed-runs policies) had no caller: no config field, no CLI command, and no code ran it. It was only kept in step with the score changes. Remove the module, its export, its build entry, and its docs. The per-state assertions of `report-records.test.ts` move to a `countCase` test in `core/scoring`, which now owns that rule; the records test keeps the regression case and the check that pooled records equal `scoreCases`. BREAKING CHANGE: the `vieval/core/processors/results` entry point is removed. Co-Authored-By: Claude Opus 5.5 <[email protected]>
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.
Problem
A run page showed
hybrid = (exact + judge) / 2: a number without a name that averaged two different questions. Other pages showedexact. For example, airievals/tts-speech-formularecorded "the listener wrote the formula back" asexactand "the reading says the meaning" asjudge, and the viewer showed their average.There were only two score slots:
reward.json, EvalScope metrics) could not be imported.Result
Scores have names and definitions:
primary. Every page, the CLI, and the leaderboard show it with its label, next to the completion rate.Comparison:
afc74d7(main, v0.9.0) →adcb7dd(head revision ofnekomeowww/feat/named-scores).The branch has five commits:
1f7c221adds thecreate-pragent skill, adapted from moeru-ai/auv.6bb1d99is the named-scores change.abf892ffixes the run summary. It counted a case that errored in its first auto attempt and passed in a later one as errored. That bug is onmaintoo.870a82fmoves the per-case scoring rule into one function,countCaseincore/scoring.scoreCases,cases.jsonlrecords, and the viewer all call it.adcb7ddremovesvieval/core/processors/results, which nothing called.API changes
recordScore— changedcontext.recordScore(0.8),context.recordScore(0.6, 'judge')context.recordScore(correct, 0.8, { rationale, grader })withcorrect = defineScore('formula.correct', { label })or a name stringdefineScore— addeddefineScore(name, { label, description, primary, combine, errors, grader })hybrid)defineScore('pass', { combine: { all: [correct, { score: natural, atLeast: 0.5 }] }, primary: true }), listed indescribeTask(..., { scores: [pass] })recordUnscored— addedcontext.recordUnscored(natural, 'grader_failed')describeTaskoptions — added{ scores: ScoreDefinition[] }announces scores before the first caserecordScorescoredexact: 1. An empty selection scoredexact: 1.errors: 'exclude' | 'zero'(defaultexclude). An empty selection has no scores. The completion rate counts each case once, by its final outcome.passedor a declared score instead of the implicitexactTaskRunOutput— changed{ coverage?: CaseCoverage, scores: RunScore[] }{ completion?, passed?, primary?, scores: ScoreSummary[] }defineTaskexecutors; build summaries withscoreCasesfromvieval/core/scoringvieval/core/scoring— changedscoreCaseOutcomes,hybridAverage,strictExactOf,CaseCoveragescoreCases,deriveScores,poolScoreSummaries,resolveHeadline,emptyScoreSummary,ScoreSummary,HeadlineResultvieval/core/runneraggregation — changedexactAverage,judgeAverage,hybridAverage,strictExactAverage,coveragescores: ScoreSummary[],completion,headlinevieval/core/assertions— removedAssertionOutcome.scoreKind,expectCustom({ scoreKind }),toRunScores(outcomes)score; record it withcontext.recordScore(definition, outcome.score)vieval/core/processors/results— removedprocessRunResults(results, { threshold, maxFailedRuns })run-summary.jsonheadlineyourself if you used itCLI changes
vieval run, project summary line… <n> runs, cases …, hybrid <mean>, coverage <rate>Pass 52% · completed 100%on its own line (with(n errored, n timed out)when some cases have no result);passed X%when no score is recorded; one line per task when the primary scores differvieval run, case counts, failure list, and resume hintcase.ended:cases 304 passed | 24 failed | 8 errored, and the 8 cases offered for resume although a later auto attempt passedcase.ended:cases 312 passed | 24 failed | 0 erroredvieval run(comparison leaderboard)hybrid, printshybrid … exact … coverage …Primary scores differ (a, b), so the rows rank by passed cases.when neededvieval report case-compare--score-kind <kind>(defaultexact)--score <name>(default: the primary score of the reports, or their only score; otherwise an error that lists the names)vieval report attemptsCOVERAGEcolumnCOMPLETEDcolumnThis report was written by an older vieval. Run it again.Report file and viewer API changes
events.jsonlschemaVersion: 2;score.recorded { kind: 'exact' | 'judge', score }schemaVersion: 3; newscore.defined { name, label?, description?, primary?, combine?, errors?, grader? };score.recorded { name, value }or{ name, unscored: { reason } }, with optionalrationale,grader,metadata,derivedrun-summary.jsonresult.overall.{exactAverage, judgeAverage, hybridAverage, strictExactAverage, coverage}schemaVersion: 2; top-level and per-projectheadline(HeadlineResult) andscoreDefinitions;resultholdsScoreSummarylistscases.jsonlschemaVersion: 1;scoreskeyed byexact/judgeschemaVersion: 2;scoreskeyed by score name (the counted value),unscored,scoreDetailsmetrics-summary.jsonScoreSummaryper score namevieval.score.exact, viewer gaugevieval.case.score.exactvieval.score.<name>in both; task spans carryvieval.task.primary_score@vieval/ui/contract)exact,judge,hybridand*Averagefields in about ten schemasScoreSummary,CaseScoring,HeadlineResult,CaseScores;scoreDefinitions,scoreRecordson case detail,scoreson metrics,scoreGraderson tasks and comparison columnslegacysource, rebuilt fromcases.jsonlunsupportedsource and state: listed, every route butGET /api/runs/:runKeyanswers 422The viewer:
Migration
recordScorecall. UsedefineScorefor labels, the primary score, and derived scores.describeTask(..., { scores }).defineTaskexecutors returnScoreSummary[].scoreCases([...outcomes], definitions)builds them.enandzh-hans), both READMEs,packages/ui/API.md, the examples, and the test projects are updated.Validation
At
adcb7dd:pnpm typecheck: passes.pnpm lint: 0 errors. Two warnings were there before this change.packages/vieval/src/cli/run.test.ts, "counts a case that errored in one auto attempt and passed in a later one as passed". It fails at6bb1d99and passes atabf892f.pnpm test:run: all 661 tests pass in the last run.packages/vieval/src/core/runner/collect.test.tssometimes times out at 5 s under full-suite load. This PR does not touch it, and it passes on its own.pnpm build: passes.packages/ui/test/projects/showcasewas run twice with the built CLI.Pass 52% · completed 100%.cases 312 passed | 24 failed | 0 errored.Sources
At
adcb7dd:packages/vieval/src/events/index.tscountCase,scoreCases), derived scores, pooling, and headline:packages/vieval/src/core/scoring/index.tsand its testspackages/vieval/src/dsl/scores.tsandpackages/vieval/src/dsl/task.tspackages/vieval/src/cli/report-records.tsandpackages/vieval/src/cli/report-artifacts.tspackages/ui/src/shared/contract.tsandpackages/ui/API.md🤖 Generated with Claude Code