feat(contracts): add versioned multi-runtime judging contracts

This commit is contained in:
2026-10-09 14:15:24 +08:00
parent 81f8dc3204
commit a5a7e40308
76 changed files with 8407 additions and 13 deletions
@@ -1,11 +1,13 @@
import base64
import json
from datetime import datetime
from uuid import UUID
from sqlalchemy import select, tuple_
from sqlalchemy.ext.asyncio import async_sessionmaker
from kf_oj.contracts.judging import MAX_SOURCE_BYTES, ArtifactReference, JudgementReport
from kf_oj.contracts.judging import MAX_SOURCE_BYTES, ArtifactReference
from kf_oj.contracts.judging_versions import decode_report
from kf_oj.contracts.submissions import (
CancellationAccepted,
PublicCaseResult,
@@ -115,7 +117,11 @@ class SubmissionQueries:
if evaluation.state in {"finished", "failed", "cancelled"} and evaluation.final_report:
# A single joined snapshot, strict validation and explicit projection prevent leaking
# internal bindings, artifacts, hidden case identifiers or partial attempt reports.
report = JudgementReport.model_validate(evaluation.final_report)
report = decode_report(
json.dumps(
evaluation.final_report, ensure_ascii=False, separators=(",", ":")
).encode()
)
if str(report.binding.evaluation_id) != str(evaluation.id):
raise ValueError("stored result binding invalid")
if report.verdict.value != evaluation.verdict:
@@ -7,10 +7,10 @@ from contextlib import asynccontextmanager
from sqlalchemy.ext.asyncio import async_sessionmaker
from kf_oj.contracts.judging import (
JobManifest,
LeaseBinding,
decode_wire,
from kf_oj.contracts.judging import LeaseBinding
from kf_oj.contracts.judging_versions import (
Manifest,
decode_manifest,
manifest_bytes,
)
from kf_oj.infra.artifacts.repository import ArtifactRepository
@@ -40,7 +40,7 @@ class WorkerAccess:
raise WorkerAccessDenied("worker grant rejected")
return hashlib.sha256(token.encode("ascii")).hexdigest()
async def _manifest(self, session, binding: LeaseBinding, token: str) -> JobManifest:
async def _manifest(self, session, binding: LeaseBinding, token: str) -> Manifest:
row = await repository.leased_submission(session, binding, self._token_hash(token))
if row is None:
raise WorkerAccessDenied("worker grant rejected")
@@ -49,7 +49,7 @@ class WorkerAccess:
# runtime roles; use canonical bytes for both retrieval and digest verification.
try:
manifest = decode_wire(JobManifest, json.dumps(attempt.manifest).encode())
manifest = decode_manifest(json.dumps(attempt.manifest).encode())
if (
manifest.evaluation_id != evaluation.id
or manifest.submission_id != submission.id