8000 Assert format: date-time on runs and 1.0 runs[]: a non-RFC 3339 started_at / ended_at is a schema error by ynishi · Pull Request #52 · ynishi/evalhub · GitHub
[go: up one dir, main page]

Skip to content

Assert format: date-time on runs and 1.0 runs[]: a non-RFC 3339 started_at / ended_at is a schema error - #52

Merged
ynishi merged 1 commit into
mainfrom
fix/date-time-format
Sep 28, 2026
Merged

ynishi merged 1 commit into
mainfrom
fix/date-time-format

Conversation

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

format: date-time is enforced: a non-RFC 3339 started_at / ended_at is a schema error

Fixes #47. The served JSON Schema has declared format: date-time on run timestamps since 0.1.0, and nothing checked it: the validators were built for Draft 2020-12, where format is an annotation unless assertions are switched on. A run with "started_at": "yesterday" was accepted, the string stayed in the body, and the runs.started_at column was NULL, so the run sorted and filtered as one with no timestamp.

Behaviour

  • compile() in evalhub-core builds every validator with should_validate_formats(true) (and should_ignore_unknown_formats(true), the crate default, made explicit). A date-time that is not RFC 3339 is 422 with one schema error at the field: /started_at, /ended_at, or /runs/N/started_at for an evalhub.eval/1.0 body. PUT …/runs/{id}, POST …/runs:batch and POST /evals/… (1.0) refuse it and write nothing.
  • An accepted run whose body carries a timestamp always fills the column: every value jsonschema accepts, DateTime::parse_from_rfc3339 parses (offsets, fractional seconds, lower-case t / z, the UTC leap second).
  • The separator between date and time must be T (or t), as RFC 3339 §5.6 has it. A space is refused, although chrono would parse it, so a body 0.3.0 accepted with a space is now a schema error.
  • Only date-time becomes an assertion. The other formats in the served schemas (double, int64, uint32, uint64, schemars' numeric hints) are unknown to jsonschema 0.56 and stay annotations.
  • Stored bodies are not re-validated; reads and the data migration do not run the validator. Runs stored by 0.3.0 or earlier may keep a non-RFC 3339 string with a NULL column. card.json and eval-2.json have no date-time field, so records are affected only through the 1.0 runs[].

Verification

cargo fmt --check, cargo clippy --workspace --all-targets -- -D warnings, cargo test -p evalhub-core (64), -p evalhub-store (97, Docker), -p evalhub-server (84, Docker); no insta snapshot changed. Core RED was observed before the fix (invalid values produced no error); the store test that pinned the old behaviour flipped to failing after the fix and was rewritten. just semver-check / just package not run (no version bump in this PR).

8000
…ed_at / ended_at is a schema error

The served schemas mark a run's `started_at` / `ended_at` (and the same
fields in `runs[]` of an Eval 1.0 body) `"format": "date-time"`, but the
validators were built for draft 2020-12 without opting in to format
assertion, so `format` was only an annotation. A run with
`"started_at": "yesterday"` was accepted, kept the string in its body and
left the `runs.started_at` column NULL, so it sorted and filtered as a run
with no timestamp, while the query side already refused the same literal
with `type_mismatch` (#47).

The core validators are now built with `should_validate_formats(true)`.
A bad value is one `schema` error at its path (`/started_at`,
`/ended_at`, `/runs/{i}/started_at`), on `PUT .../runs/{id}`, in
`runs:batch` and on `POST /evals/...` with a 1.0 body. The crate's
`date-time` check is RFC 3339 with a `T` and an offset, so a value that
passes also parses with `DateTime::parse_from_rfc3339`: an accepted run
with a timestamp always has the column. The separator must be `T`
(RFC 3339 §5.6): a space, which chrono parses and 0.3.0 therefore
accepted, is now a `schema` error.

The other formats in the generated schemas are the numeric hints schemars
emits (`double`, `int64`, `uint32`, `uint64`). jsonschema 0.56 does not
know them and ignores unknown formats by default; that is now set
explicitly, so they stay annotations. Card and Eval 2.0 have no date-time
field.

The store test that pinned the old behaviour is replaced by one that
expects the refusal and one that every accepted timestamp form fills the
column. The validate and store runs module docs say how formats and
timestamps are handled. Stored bodies are not re-validated; the rule
applies to writes.

Closes #47

Signed-off-by: Yutaka Nishimura <ytk.nishimura@gmail.com>
@ynishi
ynishi merged commit bb500ac into main Sep 28, 2026
4 checks passed
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.

format: date-time is not enforced: a run with an unparseable started_at is accepted and stored with a NULL column

1 participant

0