Horde
Update submission timeout to six hours
3b67454
|
Raw
History Blame Contribute Delete
10.9 kB
metadata
title: AV Causal Scenario Retrieval Challenge
emoji: 🔍
colorFrom: green
colorTo: gray
sdk: docker
app_port: 7860
pinned: false
hf_oauth: true
hf_oauth_expiration_minutes: 480
hf_oauth_scopes:
  - contribute-repos

AV Causal Scenario Retrieval Challenge

Public challenge site, authenticated submission intake, personal status history, and leaderboard for the NVIDIA AV Causal Scenario Retrieval Challenge. The landing page at / presents the challenge overview; the focused participation page at /participate presents the public leaderboard first, followed by the submission form and private submission history. /terms explains the exact versioned consent linked from the submission form.

The Space is a Docker/FastAPI application. It keeps the original public HTML and CSS presentation while exposing six same-origin endpoints:

  • GET /api/me returns the current HF username, locked participant profile (if established), artifact repository, and a session-bound CSRF token.
  • POST /api/artifact-repositories creates or reconnects the participant's one reusable private app-created model repository.
  • POST /api/submissions accepts public team, private contact_email, private institution, and terms_accepted: true. The first durable intake atomically locks team and institution; later requests must match before handoff begins.
  • POST /api/submissions/<id>/ingest retries handoff of the existing immutable row without creating or charging another submission.
  • GET /api/submissions returns only the authenticated user's sanitized rows.
  • GET /api/leaderboard returns the public materialized leaderboard fetched server-side from the private controller.

The unique participant identity is the rename-safe OAuth sub claim, derived from the signed Hugging Face session and stored privately as submitter_hf_id. The current preferred_username is retained as submitter_hf_user for the participant-owned artifact namespace. The first durable intake under this profile policy locks the public team display text and private institution to that stable subject; neither username nor team is used for ownership or quota checks. The browser cannot supply either HF identity, status, score, consent version/timestamp, or submission id. /api/me, personal status, results, and rendered pages never expose the raw stable ID. The additional least-privilege contribute-repos scope can access only repositories created by this OAuth app. The access token travels only in the signed OAuth session and the transient ingestion handoff; it is never logged, written to challenge datasets/results, or returned by an application API.

Official inference uses one NVIDIA A100 80 GB GPU with compute capability sm_80. Participant CUDA/PyTorch binaries must include sm_80 kernels. The participation page states this requirement, and legacy generic inference errors are rendered with an actionable entrypoint/GPU-compatibility check; true time-limit failures are reported separately by the controller. Challenge rules require the participant entrypoint to complete within six hours. The evaluator's higher operational fail-safe and outer Job deadline are infrastructure-only grace for trusted setup, validation, and output flushing; they do not provide extra participant runtime.

institution must name the participant's current university, company, research lab, nonprofit, government, or comparable formal affiliation. Independent, unaffiliated, and other explicit no-affiliation placeholders are rejected in both the browser and server. This is a participant attestation; string validation does not independently verify employment or enrollment.

The exact schema-v3 request written to the private intake dataset is:

{
  "schema_version": 3,
  "submission_id": "server-generated-uuid",
  "team": "Public Team Name",
  "submitter_hf_id": "private-rename-safe-oauth-sub",
  "submitter_hf_user": "oauth-username",
  "artifact_repo_id": "oauth-username/private-model-repo",
  "contact_email": "Private@example.org",
  "institution": "Private Institution",
  "terms_accepted": true,
  "terms_version": "2026-06-30-v4",
  "terms_accepted_at": "server-generated UTC timestamp",
  "track": "main",
  "submitted_at": "same server-generated UTC timestamp",
  "status": "QUEUED"
}

Consent evidence deliberately excludes IP addresses, user agents, OAuth tokens, and other browser fingerprints. Contact email, institution, and consent fields remain in private intake/controller storage and are omitted from status mirrors, results, and the public leaderboard. Authenticated /api/me returns only the participant's own locked team and institution so the form can enforce them; it never returns contact email or the raw stable ID. /api/me also binds the current terms version to the signed session, and intake rejects a stale session after a terms-version change until the participant refreshes and reviews the new terms. Schema-3 personal-history filtering uses exact stable-ID equality. Only legacy schema-2 status rows fall back to case-insensitive username matching.

Space configuration

Add these required Space secrets:

  • CHALLENGE_FRONTEND_TOKEN: a fine-grained service token restricted to read and write nvidia/crc-submission-intake. It must not access the controller-owned state dataset, hidden datasets, participant repositories, Jobs, or results.
  • CHALLENGE_BACKEND_TOKEN: a distinct fine-grained read-only HF gateway credential limited to the private controller Space. The frontend uses it server-side for ingestion handoff and leaderboard reads. It must never be the broad HF_CONTROLLER_TOKEN used by the controller itself.
  • CHALLENGE_INGEST_SECRET: independent shared secret checked by the backend ingestion endpoint (at least 32 random bytes).

Optional Space variables:

  • CHALLENGE_INTAKE_REPO (default nvidia/crc-submission-intake)
  • CHALLENGE_STATUS_REPO (default nvidia/crc-submission-intake)
  • CHALLENGE_BACKEND_URL (clean HTTPS private-controller origin with no path, credentials, query, or fragment; required for ingestion)
  • CHALLENGE_BACKEND_ALLOWED_HOST (default nvidia-av-causal-retrieval-challenge-backend.hf.space; the URL must match it exactly before any credential is sent)
  • CHALLENGE_TERMS_VERSION (default 2026-06-30-v4; must match the controller's CRC_TERMS_VERSION and the bundled terms.html; deployed startup fails if the frontend variable does not match the bundled document, and all versions must be bumped together whenever terms change)
  • CHALLENGE_PUBLIC_ORIGIN (normally inferred from SPACE_HOST)
  • CHALLENGE_INTAKE_LIMIT (default 5)
  • CHALLENGE_INTAKE_WINDOW_SECONDS (default 60)
  • CHALLENGE_MAX_INTAKE_BODY_BYTES (default 4096)
  • CHALLENGE_MIN_OAUTH_REMAINING_MINUTES (default 180; covers the two-hour ingestion timeout plus scheduling margin)
  • CHALLENGE_PARTICIPANT_SCOPE (defaults to SPACE_ID; keep it fixed to the exact Space id so staging and production OAuth apps use different repository names and mapping records)

The frontend writes immutable requests at intake/<submission_id>.json and reads controller-published, sanitized mirrors from status/<submission_id>.json. Those mirrors share the intake repository and are explicitly non-authoritative; the controller never trusts them. Authoritative controller state and results live behind the private controller and datasets that the frontend intake token cannot access. For the public same-origin leaderboard endpoint, the frontend server performs an allowlisted GET /api/leaderboard to the private controller using only CHALLENGE_BACKEND_TOKEN; it does not send the ingestion secret on that read. The gateway token is never returned to the browser. The frontend never receives labels, Job credentials, evaluator logs, or raw exceptions.

One deterministic mapping per stable OAuth subject and OAuth app is stored privately under participants/. The browser cannot choose or replace the repository. A separate private profiles/ pointer references the immutable first intake that locked team and institution, without duplicating institution PII. The first profile pointer and intake row are one parent-revision-guarded Hub commit, so concurrent claims cannot select different values. App-scoped names prevent staging from claiming production repositories or browser preferences. After the durable commit, the OAuth token is sent transiently to the private backend in {record, oauth_access_token} with gateway and ingestion-secret headers. If handoff fails, the existing row remains visible as retryable and a retry never writes another intake row.

The browser sends a random Idempotency-Key for initial submission creation and retains it with only a SHA-256 form fingerprint in session storage until the server confirms the immutable intake. Contact fields are not stored there. The server derives a participant-bound submission UUID from that key, so an ambiguous Hub commit response can be retried without creating a second row.

If the participant selects “Remember this email in this browser,” the browser stores only that editable email in local storage after a confirmed submission. The key uses the stable app-scoped repository suffix already returned to the participant, not the mutable username or raw stable ID. Team and institution come only from authenticated /api/me after locking; neither is browser lock evidence. Consent, tokens, and the raw stable identity are never stored in this preference.

The intake limiter is an in-process burst guard; durable attempt limits remain controller-enforced. Submission status reads cache a bounded Hub snapshot at an exact dataset revision and refresh only when that revision changes. In a deployed OAuth Space, startup fails closed if any required credential is missing, the ingestion secret is too short, or the backend URL misses the exact host allowlist.

Do not change the consent clauses in the submission form or terms.html while reusing an existing terms version. Before production, define retention and erasure procedures for the Git-backed private intake/state datasets; deleting a file only from the latest revision does not remove its historical commits.

Local development

Install dependencies and run the app:

python -m pip install -r requirements-dev.txt
uvicorn app:app --reload --port 7860

Outside a Space, the Hugging Face helper uses its documented mock OAuth flow and the locally authenticated HF account (hf auth login). Keep CHALLENGE_FRONTEND_TOKEN separate and least-privileged. To inspect only public routes without any OAuth setup, set CHALLENGE_DISABLE_OAUTH=1; submissions and personal history remain unavailable in that mode.

Run the checks with:

pytest -q
node validate-static.mjs
docker build -t crc-frontend .