Skip to content

Protected provenance and audit API

Issue #363 exposes the private trace from a submission to accepted event revisions and the statistics that currently depend on them. These routes are deliberately separate from public read endpoints so submitter identity, lifecycle history, reviewer decisions and correction audit metadata are never added to anonymous responses.

All routes require a bearer-authenticated submitter or admin account. A submitter can inspect only its own provenance. An administrator acts as a reviewer only for competitions present in that account's server-owned competitionIds; the admin role alone does not bypass competition scope.

Submission provenance

GET /api/v1/provenance/submissions returns a cursor-paginated union of direct JSON submissions, JSON/CSV file submissions and durable batches. kind=direct|file|batch can narrow the page.

Each item exposes the persistent source metadata available for that submission: original filename and media type where applicable, source byte size, SHA-256 checksum and schema/package version. Direct submissions now receive a deterministic SHA-256 checksum over the validated request payload; file submissions hash the original uploaded bytes. Batch metadata comes from the retained batch and stored_object records, so the trace remains meaningful after private raw payload expiry.

GET /api/v1/provenance/submissions/{reference} adds lifecycle history and review/publication decisions. A direct or file reference is the numeric submission ID; a batch reference is its UUID. Batch lifecycle entries come from the append-only batch_state_transition trail and decisions come from batch_review_decision.

Event revision provenance

GET /api/v1/provenance/events/{eventId} accepts the internal delivery identifier returned as a statistic contributor and returns the complete known revision lineage for that event. For each revision it exposes:

  • source submission and, where applicable, batch and batch-item references;
  • submitter identity (which may have a null display name after account tombstoning);
  • persistent checksum and current acceptance/review decision;
  • revision number, recorded/superseded timestamps and which revision is current; and
  • correction requester, reason and optional review decision from the immutable correction history.

The source link is based on retained identifiers and checksums rather than the raw payload itself.

Statistic provenance

GET /api/v1/provenance/fixtures/{fixtureId}/statistics/{statisticId} reuses the normal fixture statistic derivation with contributor tracing enabled, then resolves every current contributing delivery to its retained source provenance. The response therefore completes:

statistic -> current event revision -> submission/batch item -> submission/batch -> submitter -> decision

A submitter may read the trace only when every current contributing event belongs to that submitter. A competition-scoped administrator may review a mixed-source statistic for that competition.

Aggregate statistic provenance

GET /api/v1/provenance/participants/{participantId}/statistics/{statisticId} provides the same private trace for the published season, competition and career participant aggregates. It resolves only current accepted delivery revisions, exposes their stable sourceEventId values and source submissions, and is cursor-paginated (limit, cursor) so a career trace cannot make an aggregate response unbounded. Follow each contributor through GET /api/v1/provenance/events/{deliveryId} for its correction lineage.

Public privacy boundary

The anonymous /fixtures, /events and /statistics APIs are unchanged. They do not return submitter IDs, batch audit state, review decisions, lifecycle transitions or correction actors. Private provenance is available only from the authenticated /provenance/... routes above.

AI Declaration: This document was updated with the assistance of Codex[GPT-5].