8000 Query: a run projection target — path table, run columns, sort keys and cursor for GET /evals/{ns}/{name}/runs by ynishi · Pull Request #38 · ynishi/evalhub · GitHub
[go: up one dir, main page]

Skip to content

Query: a run projection target — path table, run columns, sort keys and cursor for GET /evals/{ns}/{name}/runs - #38

Merged
ynishi merged 1 commit into
mainfrom
feat/query-run
Sep 25, 2026
Merged

ynishi merged 1 commit into
mainfrom
feat/query-run

Conversation

@ynishi
@ynishi ynishi commented Sep 25, 2026
Copy link
Copy Markdown
Owner

Stage 3 of 9 of #24 (Runs as first-class rows), on top of stages 1–2 (#27 / #36, #28 / #37). evalhub-query gains a second target, the run projection behind GET /evals/{ns}/{name}/runs (stage 7). The grammar does not change. Mergeable on its own; the version bump is stage 9 (#35).

What changed

  • PathTable::for_runs(cards: &[CardRef]) (typecheck.rs), built by hand: run_id, status, error.kind, started_at, ended_at, the run facet leaves (the same key set as the Eval header's facets, read from the eval-2 document so the two cannot drift: 58 leaves over model / task / harness / generation / trial / env), fingerprint.{facet} for the six, metrics[{ns}/{name}] (number; any well-formed id, registry not consulted), results[{card}][{metric}].value (number) / .label (string) for the Cards named in the request, ext.* through the existing with_ext. Bracket form for parameters because slugs carry . and /; metrics.x, results.c.m.value, bare metrics / results, a malformed id, a Card not in the request, an @seq card ref and a field other than value / label are unknown_path with a hint naming the bracket form. any on a run path is type_mismatch (no array paths). Every run path is fully indexed (the projection is scoped to one Eval); an unregistered ext key keeps eq / exists only.
  • ir.rs: Column::Run(RunColumn) with RunColumn { RunId, Status, ErrorKind, StartedAt, EndedAt, Facet(path), Fingerprint(facet), Metric(id), Result { card, metric, field } }, ResultField { Value, Label }, CardRef ({ns}/{name}, validated with is_valid_id, joined at the Card's latest live version), SortKey::Run(RunColumn), RunQuery { cards, filter, sort, limit, cursor } (default order run_id ascending), RunCursor { keys, run_id } since Cursor hard-codes version_id as the tie-breaker; a record cursor does not deserialise as a run cursor. Column::Ext / Column::Body in a RunQuery are paths below the run's body.
  • compile_runs(request, table, limit, cursor) -> RunQuery, mirroring compile; expand / version are record concepts and are not read. include=archived,deleted and which Cards a caller may name are server concerns.
  • grammar.rs doc no longer lists runs among the array paths any applies to (it contradicted typecheck.rs); record queries do not gain runs. The record table is still built from RecordKind::Eval.schema() (2.0); nothing reads 1.0. Record snapshots are unchanged.
  • Timestamps: started_at / ended_at are strings in the DSL; the backend compares them as timestamps. Written on RunColumn::StartedAt and in the typecheck.rs table for stage 5 to read.
  • evalhub-store/src/query_sql.rs: Column and SortKey are exhaustive public enums, so three match arms now refuse a run column with StoreError::QueryUnsupported. No store behaviour added.
  • Crate doc (lib.rs): the second target and its path table. ir.rs / typecheck.rs module docs cover the run table.
  • Tests (tests/runs.rs, 12): typecheck of each path kind; an exact assertion of the 69 fixed paths; rejection of results[{card}] for an unnamed Card, a malformed metric id, the dotted forms; CardRef parsing; RunCursor round-trip and key-count mismatch; hints free of double spaces; and an insta snapshot (runs__runs.snap) of the IR for a query filtering on status, metrics[a/b] and results[c/d][a/b].value and sorting on metrics[a/b].

Verified

Command Outcome
cargo fmt --check clean
cargo clippy --workspace --all-targets -- -D warnings clean
cargo test -p evalhub-query 27 passed (compile 15, runs 12); record snapshots unchanged, no .snap.new
cargo test -p evalhub-store (Docker) 67 passed
cargo test -p evalhub-server (Docker) 60 passed
cargo doc --no-deps -p evalhub-query 0 warnings

Not run: cargo deny check (no dependency change), cargo sqlx prepare --check (no SQL change), just e2e, just semver-check (adding variants to Column / SortKey is a break in evalhub-query's public API; the 0.2.0 bump of stage 9 covers it, as #24 states).

Notes for the reviewer

Refs #29

…sort keys and cursor

Stage 3 of #24. GET /evals/{ns}/{name}/runs (stage 7) needs a query
target that is not a record: rows are runs of one Eval, joined with
the run_results of the Cards the caller names. The grammar (where /
sort / limit / cursor) is shared; the projection is a second target
with a path table of its own, built by hand rather than from a
RecordKind schema.

PathTable::for_runs(cards) resolves run_id, status, error.kind,
started_at, ended_at, the run's facet leaves (the same key set as
the Eval header's facets, taken from the eval-2 document, so the two
cannot drift), fingerprint.{facet}, metrics[{ns}/{name}] (a number,
any well-formed id, the registry is not consulted), and
results[{card}][{metric}].value / .label for the Cards in the
request; ext.* goes through with_ext as before. Parameters use the
bracket form the results[{metric}].value sort key already uses,
because slugs carry `.` and `/`; the dotted forms are refused with a
hint that names the bracket form. A CardRef is {ns}/{name}, joined
at the Card's latest live version.

ir gains Column::Run(RunColumn), SortKey::Run, RunQuery and
RunCursor { keys, run_id }: Cursor hard-codes version_id as the
tie-breaker and a record cursor must not deserialise as a run
cursor. compile_runs mirrors compile. Which Cards a caller may name
and include=archived,deleted are server concerns, not part of the
DSL. Timestamps are strings in the DSL; the backend compares them as
timestamps (written where stage 5 reads it).

Column and SortKey are exhaustive public enums, so evalhub-store's
query_sql.rs gains three arms that refuse a run column with
QueryUnsupported; no store behaviour is added. The grammar doc no
longer lists `runs` among the array paths, which typecheck.rs had
contradicted since the path table was built.

Verified: cargo fmt --check; cargo clippy --workspace --all-targets
-D warnings; cargo test -p evalhub-query (27 passed: compile 15,
runs 12; record snapshots unchanged, one new run snapshot);
cargo test -p evalhub-store (67, Docker); cargo test -p evalhub-server
(60, Docker); cargo doc --no-deps -p evalhub-query (0 warnings).

Refs #29

Signed-off-by: Yutaka Nishimura <ytk.nishimura@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

0