Repository navigation
Release 0.2.0: runs as first-class rows - #44
Merged
Merged
Conversation
…0.2.0 client mapping (0.2.0) Stage 9 of #24, the last: documentation and the bump, no production code. README gains the run projection's path table in bracket form with the query rules and an example, the [limits] keys with their env form and defaults, the schema ids as served (eval-2 and run are new, eval stays the 1.0 document until 0.3.0, card covers 1.1 and 1.0), and a section on upgrading from 0.1.x: a POST with runs becomes a header POST plus run PUTs, outcome becomes the run's status plus the Card's run_results, evalhub.eval/1.0 with runs is accepted and converted in 0.2.0 only with a Deprecation header and 0.3.0 refuses it with runs_moved, the returned content_hash of a converted body is the 2.0 header's, re-posting a body that omits a run no longer drops that run, header hashes change on migration with old and new in the audit log, versions that differed only in runs become identical header versions, and Card relations keep resolving because they point at version ids. The five crate docs each name the model as it applies to the crate: header plus runs, the used set, the four hashes, the visibility of runs and run_results, where the limits live, and the data migration as the one exception to write-once versions. Two stale claims went: the store doc offered export?format=bundle, which answers 501, and the server doc described 0.3.0's refusal differently from README. cargo semver-checks against 0.1.4 on crates.io: evalhub-schema 5 major lints (Eval.runs, eval::Run and eval::Outcome removed, Card.run_results and the ErrorCode variants added), evalhub-query 1 major (Column::Run and SortKey::Run on exhaustive enums), evalhub-core no update required. On 0.x that is the minor bump: [workspace.package] version and the four internal pins go to 0.2.0 and cargo update -w moves the five workspace entries in Cargo.lock and nothing else. Verified: cargo fmt --check; cargo clippy --workspace --all-targets -D warnings; cargo test -p evalhub-schema (20), -core (62), -query (27), -store (96, Docker), -server (82, Docker); just sqlx-check against a migrated throwaway Postgres; cargo deny check (advisories, bans, licenses, sources ok); cargo doc --no-deps with -D warnings for the five crates; just semver-check before the bump (above) and after (all lints skipped at the new major). just package and just e2e run on this commit are in the pull request body. Refs #35 Signed-off-by: Yutaka Nishimura <ytk.nishimura@gmail.com>
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.
0.2.0 makes an Eval's runs first-class. An Eval is now a versioned header plus a set of runs that belong to the record, not to a version: each run is a row written by
run_id, with its own conditions (the header's facets as defaults),status,metricsand attachments, and it can be overwritten, archived or deleted without appending a header version. The verdict on a run moves to the Card (run_results), andGET /evals/{ns}/{name}/runsreads runs × metrics × the chosen Cards' judgements in one page. Four hashes keep it verifiable: the header'scontent_hash, each run'scontent_hash, the record'sruns_hash, and a Card's used-set hash, from whichchanged_since_cardis derived. This is the 9-stage change of #24, landed as one release.Upgrading a hosted database
evalhub migratefor 0.2.0 applies the0003DDL and then a one-shot data migration,0003_runs_split, recorded indata_migrationsso it never runs twice.serverefuses to start until both have run.8000- Runs are collected from every live 1.0 version by
- Every live 1.0 version body becomes its 2.0 header (no
- Each Card's used runs are rebuilt from the Eval version it points at, so a run that changed since shows as changed at once. A Card's relations keep resolving because they point at version ids, not hashes. Used run ids with no run are skipped and recorded as
- The step is one transaction: a failure (or the release command's 5-minute timeout) rolls it back and leaves it pending. A
run_id(highestseqwins) and become rows.pass/fail→ok,error→errorwitherror.kind: unrecorded,skipped→skippedwithskip_reason: unrecorded; the droppedoutcomeis kept asmeta.v0.2.0_migration.outcome; the source version's header facets are copied onto each run.runs,schema2.0). Headercontent_hashvalues change; the old and new hash of every version are in the audit log (migration.runs_split). Versions that differed only inrunsbecome identical header versions.migration.card_runs_unmatched(0.1.x never checkedattrs.runs); these are expected, not errors.run_idit cannot accept is named in the error, and nothing is written.Production deploy (
docs/hosting.md, "Upgrading to 0.2.0"; not the plainfly deployof other releases), from the checkout of thev0.2.0tag:fly volumes snapshots create <volume-id> --app evalhub-db(and apg_dump).fly machine update <machine-id> --autostart=false --skip-start --app evalhub, thenfly machine stop <machine-id> --app evalhub;/api/v1/healthzmust fail. Otherwise the old binary can store a 1.0 body after the migration and nothing would split it.fly deploy --ha=false. The release command logsapplied data migration 0003_runs_split: …. If the Machine is still stopped afterwards,fly machine start <machine-id> --app evalhub.fly releases --app evalhubandfly ssh console --app evalhub -C "evalhub --version"(→evalhub 0.2.0);/api/v1/healthzand/openapi.json(info.versionstays the contract's1.0.0) confirm liveness only.bash deploy/fly/smoke.sh(header POST, two run PUTs, a Card withrun_results, the projection, anonymous reads after publishing).Upgrading a client
POST /evals/{ns}/{name}withruns[]in the bodyPOSTthe header withoutruns, thenPUT …/runs/{run_id}per run orPOST …/runs:batchruns[].outcome(pass/fail/error/skipped)status(ok/errorwitherror.kind/skippedwithskip_reason), and the pass / fail in the Card'srun_results[]"schema": "evalhub.eval/1.0""schema": "evalhub.eval/2.0"(GET /schemas/eval-2)"schema": "evalhub.card/1.0""schema": "evalhub.card/1.1"(addsrun_results);evalhub.card/1.0is still acceptedevalhub.eval/1.0body withruns[]is accepted and converted in 0.2.0 only: stored as a 2.0 header plus run rows, with aDeprecation: @1790294400header (RFC 9745),converted_from: "evalhub.eval/1.0"andconverted_runsin the response. 0.3.0 rejects it with422 runs_moved, as 0.2.0 already does for a 2.0 header carryingruns. The issue for that removal is opened when 0.2.0 lands, with its date.content_hashis the converted 2.0 header's, not the hash of the posted body; and re-posting a body that omits a run no longer drops that run (runs are rows now; archive or delete it).PUTmust carryrun_idin the body, equal to the path's.API
/api/v1/evals/{ns}/{name}:PUT /runs/{run_id}(201 created / 200updated/ 200unchanged),POST /runs:batch(all or nothing; a refusal lists every failing element),GET /runs(the projection:cards=,where,sort,limit1–200,cursor,include=archived,deletedfor members),GET/PATCH(archived) /DELETE(tombstone)/runs/{run_id}. Runs follow the Eval's visibility; every route is404for an Eval the caller may not see.run_id,status,error.kind,started_at,ended_at, facet keys (model.id, …),fingerprint.{facet},metrics[{ns}/{name}],results[{card}][{metric}].value/.label,ext.*. Per Card the page reportsruns_used,used_set_hash,posted_used_set_hashandchanged_since_card.GET /evals/{ns}/{name}[@…]carriesruns: { count, by_status, archived, deleted, runs_hash }(archived / deleted for members only). The comparison view (GET /evals/…/cards) comparessame_harness/same_modelagainst every run a Card used and addsruns_used,used_set_hash,changed_since_card.run_resultsentries that name an Eval the reader may not see are removed and counted inwithheld.run_results(GETandPOST /cards/query); a writer naming a run of an Eval they may not see getsrun_unknown, as for a missing run.[limits]):body_bytes16 MiB (413 body_too_large, every endpoint; was axum's 2 MiB default),batch_runs1,000 (413 batch_too_large),run_results100,000 per Card version (422 too_many_run_results). Refused, never truncated.GET /schemas/eval-2(the header) andGET /schemas/runare new;GET /schemas/evalstays the 1.0 document until 0.3.0.runs_moved,run_status_detail,run_id_invalid,run_id_mismatch,run_result_value_or_label,run_results_eval_unknown,run_unknown,run_not_in_used_set,too_many_run_results,batch_duplicate_run_id(422);run_deleted(409);batch_too_large,body_too_large(413).run.create/run.update/run.archive/run.unarchive/run.delete,migration.runs_split,migration.card_runs_unmatched.info.versionof/openapi.jsonstays1.0.0.Crates
evalhub-schema,evalhub-coreandevalhub-queryare published at 0.2.0 (the store and the server ship asghcr.io/ynishi/evalhub:0.2.0).just semver-checkagainst 0.1.4 on crates.io, before the bump:evalhub-schemaEval.runsremoved,eval::Runandeval::Outcomeremoved,Card.run_resultsadded to an exhaustively constructible struct, 13ErrorCodevariants addedevalhub-coreevalhub-queryColumn::RunandSortKey::Runadded to exhaustive enumsAt 0.2.0 the same command reports "no semver update required" for all three (0 checks, 254 skipped: a major bump skips the lints).
Changes by stage
runsin an Eval body, check run_results, fingerprint a run, publish the run hash formulas #28)GET /evals/{ns}/{name}/runs#29)[limits], schema ids, Upgrading from 0.1.x), the crate docs' final pass, the 0.2.0 bump (Release 0.2.0: README endpoints and limits, crate docs, semver check, bump, release notes with the 0.1.x → 0.2.0 client mapping #35)Verified
cargo fmt --checkcargo clippy --workspace --all-targets -- -D warningscargo test -p evalhub-schemacargo test -p evalhub-corecargo test -p evalhub-querycargo test -p evalhub-store(Docker)cargo test -p evalhub-server(Docker).snap.newjust sqlx-check(throwawaypostgres:16-alpine, migrations 0001–0003)cargo deny checkRUSTDOCFLAGS=-D warnings cargo doc --no-deps(five crates)just semver-check(before the bump)just semver-check(at 0.2.0, on the commit)just package(on the commit)evalhub-schema66422,evalhub-core75555,just e2e(on the commit)e2e: 18 passed, 0 failed; Playwright 6 passedCargo.lockevalhub-*versions changedNot run:
deploy/fly/smoke.sh(targets the hosted service; step 5 above, after the deploy).Closes #24
Refs #35