From bfdc165ce8a687468b5444ded302a6c0bbf5fb92 Mon Sep 17 00:00:00 2001 From: tryeverything24 <114252040+tryeverything24@users.noreply.github.com> Date: Fri, 24 Jul 2026 20:50:12 +0300 Subject: [PATCH] fix(validator): return submission evaluations in chronological order The submission detail serializer computed a chronologically sorted "ordered_evaluations" list but only used it for an unused local variable, building the response from the unordered relationship instead. Trains were already ordered, so evaluations and trains came back in inconsistent order. Serialize evaluations from the sorted list (matching trains) and drop the dead variable. Adds a regression test covering both orderings. --- validator/src/eval_backend/api/routes.py | 3 +- validator/tests/test_submission_schema.py | 57 +++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 validator/tests/test_submission_schema.py diff --git a/validator/src/eval_backend/api/routes.py b/validator/src/eval_backend/api/routes.py index 8b1b5fc..713c65b 100644 --- a/validator/src/eval_backend/api/routes.py +++ b/validator/src/eval_backend/api/routes.py @@ -101,7 +101,6 @@ def _submission_to_schema(submission: Submission) -> SubmissionOut: submission.trains, key=lambda run: (run.created_at or _utcnow(), run.id), ) - latest = ordered_evaluations[-1] if ordered_evaluations else None evaluations = [ EvaluationOut( id=run.id, @@ -140,7 +139,7 @@ def _submission_to_schema(submission: Submission) -> SubmissionOut: created_at=run.created_at, deleted_at=run.deleted_at, ) - for run in submission.evaluations + for run in ordered_evaluations ] trains = [ TrainOut( diff --git a/validator/tests/test_submission_schema.py b/validator/tests/test_submission_schema.py new file mode 100644 index 0000000..1b3c5e1 --- /dev/null +++ b/validator/tests/test_submission_schema.py @@ -0,0 +1,57 @@ +from __future__ import annotations + +from datetime import datetime, timedelta, timezone + +from eval_backend.api.routes import _submission_to_schema +from eval_backend.models import EvaluationRun, Submission, TrainRun + + +def _submission() -> Submission: + now = datetime.now(timezone.utc) + return Submission( + id="sub-order", + source="github_pr", + miner_id="miner-a", + benchmark_names_json=["math500"], + status="completed", + created_at=now, + updated_at=now, + ) + + +def _evaluation(eval_id: int, created_at: datetime) -> EvaluationRun: + return EvaluationRun(id=eval_id, status="completed", created_at=created_at) + + +def _train(train_id: int, created_at: datetime) -> TrainRun: + return TrainRun(id=train_id, status="completed", created_at=created_at) + + +def test_submission_schema_orders_evaluations_chronologically() -> None: + base = datetime(2026, 1, 1, tzinfo=timezone.utc) + older = _evaluation(1, base) + newer = _evaluation(2, base + timedelta(hours=1)) + + submission = _submission() + # Relationship contents can arrive in any order (e.g. DB row order); the + # serialized detail response must still be chronological, like ``trains``. + submission.evaluations = [newer, older] + submission.trains = [] + + out = _submission_to_schema(submission) + + assert [run.id for run in out.evaluations] == [1, 2] + + +def test_submission_schema_orders_trains_chronologically() -> None: + base = datetime(2026, 1, 1, tzinfo=timezone.utc) + older = _train(1, base) + newer = _train(2, base + timedelta(hours=1)) + + submission = _submission() + submission.evaluations = [] + submission.trains = [newer, older] + + out = _submission_to_schema(submission) + + assert [run.id for run in out.trains] == [1, 2]