--- 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 registration/submission form and private submission history. `/dataset` and `/terms` are available only to authenticated participants whose team registration has been accepted. The public landing page deliberately omits dataset identity, download links, task splits, training examples, and detailed development instructions. The protected dataset page supplies those resources; the protected terms page contains the exact versioned Agreement linked from the submission form. The `/dataset` gate controls disclosure through the challenge frontend. The Official Terms identify the underlying dataset as publicly available, so this application cannot revoke direct access for someone who independently already knows an upstream public URL. The Space is a Docker/FastAPI application. It keeps the original public HTML and CSS presentation while exposing same-origin participant APIs: - `GET /api/me` returns the current HF username, locked participant profile (if established), artifact repository, and a session-bound CSRF token. - `POST /api/registrations` accepts public `team`, private `contact_email`, and private `institution`. It creates a team-registration request for organizer review without collecting terms acceptance. - `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 server fixes every participant submission to the canonical `main` online-container track. The first durable intake atomically locks team and institution; later requests must match before handoff begins. - `POST /api/submissions//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. Participants publish a self-contained devkit-built container artifact to the private model repository created by the frontend; the private backend copies and runs that immutable artifact revision. `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: ```json { "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-08-v1", "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-08-v1`; 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/.json` and reads controller-published, sanitized mirrors from `status/.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: ```bash 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: ```bash pytest -q node validate-static.mjs docker build -t crc-frontend . ```