Status: FROZEN for challenge_id = "design", challenge_scoring_version u16 = 2.
Normative contract for the design challenge on Base. Byte-level epoch bundle
rules live in BUNDLE_SPEC.md (protocol_version = 1).
Pin map for CI: DESIGN_CHALLENGE_CHECKLIST.md.
Gate: cargo run -p xtask -- design-check.
This challenge replaces agent-v1 (Phala CVM) and hypertraining. Miners submit Python harness source over HTTP — no miner-provided Docker image, no Phala/CVM path.
Miner --POST /v1/harness--> design-challenge (:8093)
|
round clock (10/day UTC) + quota
|
+-------------v--------------+
| design-sandbox (two phase) |
| install → run |
| image: design-runtime |
| net: design-sandbox-egress|
+------+---------------------+
| HTTP only
+------v---------------------+
| design-egress-proxy |
| open egress, internal |
| blocklist; OpenRouter key |
+----------------------------+
|
/out/pages/*.html
|
design-sanitize → store (postgres)
|
+----------------+----------------+
| |
viewer (index.png agentic review → admin winners (1|2)
screenshots only; |
HTML never served) exact-E leaves → gateway /v1/weights/raw
| Process | Host | Holds design_sk? |
Holds OpenRouter key? |
|---|---|---|---|
design-challenge |
master only | yes (file mount) | yes (agentic review; optional Sim) |
design-egress-proxy |
master only | no | yes (sandbox LLM path) |
| sandbox container | master (ephemeral) | never | never |
| gateway | master | no | no |
| validator | validators | no | no — no challenge exec; fetch sealed weights only |
Evaluation (sandbox, sanitize, AgenticReview, admin winners, leaf emit) is
master-only. Validators never run design-challenge / egress / socket-proxy.
Sandbox containers attach only to the internal Docker network
design-sandbox-egress. The sole reachable peer is design-egress-proxy.
| Field | Value |
|---|---|
challenge_id |
design |
challenge_scoring_version |
u16 = 3 |
SCORE_MAX |
1_000_000 |
| Listen port | 8093 (local overlay 28093) |
| Gateway proxy prefix | /challenge/design/* |
Bundle protocol_version |
1 (BUNDLE_SPEC.md) |
emission_share_bps |
0 (prism 100%; sum 10000) |
| Policy | all_metagraph_hotkeys |
| Round length | ROUND_SECS = 8_640 (10 rounds / UTC day) |
| Agent run timeout | AGENT_RUN_TIMEOUT_SECS = 1_800 (30 min; distinct from round length) |
| Scoring window | SCORING_WINDOW_ROUNDS = 10 (rolling round-win points share) |
round_id |
floor(unix_secs / 8640) |
Domain round_id |
base-design-round-id-v1 |
| Domain submission | base-design-submission-v1 |
| Domain pair | base-design-pair-id-v1 |
| Domain run | base-design-run-id-v1 |
| Raw-weight domain | base-rawweight-v1 (via bundle) |
Staging knobs (defaults above are the prod pins and never change implicitly):
DESIGN_ROUND_SECS, DESIGN_AGENT_RUN_TIMEOUT_SECS, DESIGN_PROMPTS_PER_ROUND
override round length / run timeout / prompts per round (staging uses ~15-minute
rounds; env-staging.yml).
Emission posture: emission_share_bps = 0 for design and 10000 for prism
(100% prism; sum 10000). Rebalance via the owner ceremony in
runbooks/design-enable-and-emission.md
and config/challenges.toml.
Miners submit source, not images. Preferred transport is ZIP
(Content-Type: application/zip + X-Miner-Hotkey, or JSON zip_base64).
JSON with inline agent_py / pyproject_toml remains accepted for local/CI.
Optional env_vars (JSON map or X-Env-Json on ZIP) are injected into the
sandbox run phase only. Keys must match [A-Z][A-Z0-9_]*; operator /
proxy prefixes (DESIGN_, HTTP_, PYTHON…, …) are rejected. Values are
never logged.
| File | Rule |
|---|---|
agent.py |
Must define def run(task, llm, out) -> None |
pyproject.toml |
Required; deps installed in sandbox install phase |
| Extra files | ≤ 16 files, ≤ 256 KiB each, total bundle ≤ 1 MiB |
harness_id = sha256(base-design-submission-v1 || hotkey || agent || pyproject || extras || env).
POST /v1/harness is idempotent on that digest.
- The miner hotkey must be in the metagraph (bulk cached snapshot, 15m
TTL fail-closed; no per-UID RPC on the request path). Unknown hotkey →
403 hotkey_not_in_metagraph; snapshot missing/stale →503 metagraph_unavailable. - One accepted submission per
(challenge, hotkey)(submission_gatingtable). While the row isregistered/blocked/rejected, a different harness from the same hotkey →409 submission_gated. The identical re-POST stays idempotent (200 already-queued). - Auto round enqueue:
POST /v1/harnessschedules the harness intoround_id(now) + 1([RunOrigin::Manual]). On every subsequent open round the orchestrator auto-enqueues the latest active harness per hotkey into that round with the round's shared prompt ([RunOrigin::Scheduled]) — idempotent if already queued. Eliminated harnesses (eliminated_until_round > rid) are skipped. Infra auto-retry on the same run id (up to 3) is not a new schedule. Ops may stillPOST /v1/admin/rounds/current/requeue(same enqueue path). - Auto-retry: infra-class failures (
install,ast_infra,llm_infra) requeue automatically up to 3 times;cheat/rejected/ admin reject / unscored timeout are terminal. Budget exhaustion →failed+ gatingblocked. ManualPOST /v1/runs/{id}/retryis unchanged. - A metagraph watcher reopens eligibility (
open) when the hotkey leaves the metagraph (uid deregistered or hotkey replaced), so the same hotkey may resubmit under a new uid. The hotkey is never permanently burned. - Miner env (
env_vars) is locked at submission into the stored bundle; changing it requires a new digest (and a free gating slot).
index.htmlpricing.htmlcomponents.htmlmanifest.json(present in operator harness layout; pages gated by sanitize)
task.prompt,task.round_id,task.pages_required,task.budgetllm.chat(messages, model)→ HTTP to egress proxy (no key in harness)out.write_page(name, html),out.write_asset(name, bytes)(size-capped)
Operator entrypoint design_harness.py loads miner agent.py after install.
Two phases on pinned design-runtime:
- install —
pip install --no-cache-dir -e /workinto a work-root venv, resolvingpyproject.tomldeps from PyPI via the egress proxy (open Internet; internal-target blocklist). Miner env is not injected in this phase. TimeoutDESIGN_INSTALL_TIMEOUT_SECS(default 300s); non-zero exit or timeout → error classinstall(auto-retry ≤ 3, thenfailedwithNoScore(ChallengeInternal)). - run — same work root; open egress via the proxy for external APIs /
MCP servers (same blocklist);
llm.chatrides the budgeted/v1/chatpath; miner env injected; loadsdesign_harness.py.
The egress proxy blocklist refuses cloud metadata (169.254.169.254),
loopback, RFC1918/VPC (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16),
CGNAT (100.64.0.0/10), and control-plane service names, enforced after
DNS resolution (DNS-rebinding safe).
docker-engine RunSpec hardening for design (prefix base-design-):
ReadonlyRootfs: true+ bounded tmpfs/tmpCapDrop: ["ALL"]SecurityOpt: ["no-new-privileges:true"]PidsLimit,Memory,MemorySwap,NanoCpussetNetworkMode: design-sandbox-egress(pre-created; socket-proxy denies Networks API)User: 65532:65532- Wall-clock timeout → stop/rm
Host SimSandbox is fail-closed outside explicit non-prod/CI opt-in
(BASE_ALLOW_HOST_SIM=1 + non-prod, typically via env-local.yml or e2e).
Staging/prod paths are Docker-only via socket-proxy — no silent fallback.
Floating tags (:latest) are forbidden for design-runtime / challenge images in prod pins — digest-only.
Ingestion via design-sanitize (ammonia + CSS filter). Produced HTML is
never served — sanitized pages are orchestrator input only (screenshot
capture, anti-cheat review); the public viewer serves PNG screenshots
only (§6).
- Tags:
script,iframe,object,embed,applet,base,form,meta[http-equiv=refresh],link[rel=import], scriptable SVG - All
on*event attributes - URL schemes: reject
javascript:,vbscript:,data:text/html; allowhttp,https,mailto,data:image/* - CSS: soft-strip
@import …;rules (remainder of the<style>block is kept); hard-reject (drop the whole block/attr) forexpression(,url(javascript:, IE-onlybehavior:(notscroll-behavior:),-moz-binding - External
<link rel=stylesheet>is stripped (no CDN / Tailwind CDN); miners must embed presentation CSS in<style>or inlinestyle=for screenshots and the sandboxed viewer to look styled
sanitize_report (including js_stripped) is stored and shown to annotators.
JS stripped is not an automatic Score(0) — only a visible signal. Invalid /
missing required pages → automatic Score(0) at scoring gates.
GET /v1/view/{run_id}/{page} serves PNG screenshots only (image/png,
private, no-store, nosniff). Produced HTML is never served: requests
for .html pages (or bare page names) return 410 Gone with a short JSON
error, and GET /v1/runs/{id}/bundle.json no longer embeds page HTML (same
410 Gone contract — use /v1/runs/{id}/pages for page metadata). Miner
output reaches browsers exclusively as the captured index.png screenshot.
PNG screenshots (*.png) leave the gateway with a light header floor so
marketing UIs can load them with a direct absolute URL (no Vercel proxy of
image bytes):
X-Content-Type-Options: nosniff
Referrer-Policy: no-referrer
Cross-Origin-Resource-Policy: cross-origin
Cache-Control: private, no-store
Example: https://chain.joinbase.ai/challenge/design/v1/view/{run_id}/index.png.
JSON/site API calls may still use the site's /gbase-api rewrite; <img src>
for screenshots should not.
Non-PNG /challenge/{id}/v1/view/* responses (e.g. HTML 410 Gone, or a
stale upstream that still served miner HTML) keep the full lockdown floor:
Content-Security-Policy: sandbox; default-src 'none'; img-src data: https:; style-src 'unsafe-inline' https:; font-src data: https:; base-uri 'none'; form-action 'none'; frame-ancestors <allowlist>
X-Content-Type-Options: nosniff
Referrer-Policy: no-referrer
Cross-Origin-Resource-Policy: same-origin
Cross-Origin-Opener-Policy: same-origin
Permissions-Policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()
Cache-Control: private, no-store
The sandbox directive is emitted without allow-scripts and without
allow-same-origin: even if a stale or misbehaving challenge upstream served
miner HTML through the gateway, it would run in an opaque origin with script
execution disabled, unable to read the serving origin's cookies, storage, or
DOM. All view responses never carry Set-Cookie (the gateway strips it);
the endpoint stays public (run_id is the capability) and reads no auth cookie.
frame-ancestors <allowlist> defaults to
'self' https://joinbase.ai https://*.vercel.app http://localhost:*
(DESIGN_FRAME_ANCESTORS / BASE_GATEWAY_VIEW_FRAME_ANCESTORS override).
Screenshots-only serving makes miner HTML unreachable in the first place; the non-PNG header floor is the second line.
After sanitize, the orchestrator renders the sanitized index.html artifact
(store → temp file → file://) in headless Chromium inside the
design-challenge container — never the public /v1/view URL (screenshots-only;
the stored artifact is the capture source of truth).
Chromium runs --no-sandbox because the renderer sandbox needs user
namespaces / CAP_SYS_ADMIN, which Docker does not grant. Defense-in-depth for
screenshot SSRF (sanitizer-missed script, or static http(s) / CSS url(...)
to gateway / metadata / socket-proxy / postgres on the shared base network):
- Sanitize — ammonia strips scripts/handlers;
href/srcto control-plane hostnames, link-local/metadata, and RFC1918 literals are rewritten to#. - Egress proxy — Chromium is launched with
--proxy-server=$DESIGN_SCREENSHOT_PROXY(compose defaulthttp://design-egress-proxy:8094) and--proxy-bypass-list=<-loopback>so even loopback/metadata attempts traverse the same internal-target blocklist as miner sandboxes (post-DNS IP deny). EmptyDESIGN_SCREENSHOT_PROXYdisables the force (local stub tests only). - Capture CSP — the throwaway
file://document uses a nonce-lockedscript-src(height probe only),connect-src 'none', andnavigate-to 'none'(CLI Chromium has no Playwright route hooks).
Produced HTML is still never served to browsers. Two passes (measure height via
--dump-dom, then --screenshot --window-size=1280×H), hard process timeout,
one retry; failure never fails the run. The PNG is stored as the index.png
artifact (base64) and served at GET /v1/view/{run_id}/index.png (image/png,
private, no-store, nosniff, Cross-Origin-Resource-Policy: cross-origin);
run detail exposes screenshot_url when the artifact exists. Public sites
should point <img src> at the absolute gateway host (e.g.
https://chain.joinbase.ai/challenge/design/...) rather than proxying PNG
bytes through a CDN edge.
Backfill (idempotent; upserts on (run_id, path) so it can be re-run and can
race a live capture safely):
# on the master host, from the repo checkout (env comes from the container):
docker compose -f docker-compose.yml -f deploy/compose/role-master.yml \
-f deploy/compose/env-prod.yml exec design-challenge \
design-challenge backfill-screenshots --limit 500When historical rows were sanitized by a buggy filter that wiped <style>
(raw still has CSS; sanitized does not), backfill-screenshots is not enough —
it only re-renders the already-broken sanitized HTML and skips runs that already
have index.png. Use re-sanitize from raw_html (throttled Chromium):
docker compose -f docker-compose.yml -f deploy/compose/role-master.yml \
-f deploy/compose/env-prod.yml exec design-challenge \
design-challenge backfill-resanitize --limit 500 --sleep-ms 2000
# or pin specific runs:
# design-challenge backfill-resanitize --run-id <id> --run-id <id2> --sleep-ms 2000-
Round every
ROUND_SECS = 8_640(10 rounds / UTC day):round_id = floor(unix_secs / 8640). -
Registration waits for the next round: an accepted harness is scheduled into
round_id(now) + 1and its runs only become claimable once that round opens — never into the round already in flight. After that, the round loop auto-enqueues every eligible active harness into each newly opened round (same shared prompt; Scheduled origin; idempotent). -
Agent run timeout:
AGENT_RUN_TIMEOUT_SECS = 1_800(30 minutes wall clock for the sandbox run phase — not the round length). -
Prompts: repo-pinned bank (
bank_v1.json, no human approval API); deterministic weighted drawSHA256(domain || round_id || bank_digest)→ 1 prompt per round (PROMPTS_PER_ROUND = 1); identical for every harness in that round. -
Quota (two buckets, per hotkey per UTC day) — organizer-scheduled work does not draw on the miner's anti-spam allowance:
Bucket Charged by Cap Override Manual POST /v1/harness(miner-initiated next-round schedule)MANUAL_DAILY_RUN_QUOTA = 10DESIGN_MANUAL_DAILY_RUN_QUOTAScheduled Round-loop auto-enqueue + admin/rounds/current/requeuerounds/day × prompts/round × SCHEDULED_DAILY_RUN_HEADROOM(= 20 at 10 rounds × 1 prompt)DESIGN_SCHEDULED_DAILY_RUN_CAP(clamped ≥ the day's own schedule)Enforcement is per bucket: exhausting manual submissions never stops the round scheduler, and the scheduled cap is a runaway-scheduler guard, not a participation limit (a harness active all day stays under the floor of
scheduled_runs_per_day).GET /v1/quota/{hotkey}reports both. -
Auto-retry: infra-class failures (
install/ast_infra/llm_infra) requeue up to 3 times (DESIGN_AUTO_RETRY_MAX), then terminalNoScore(ChallengeInternal)+ gatingblocked. -
Automatic gates →
Score(0): invalid bundle, missing pages, timeout, crash. -
Operator / infra fault →
NoScore(ChallengeInternal).
Stages after sanitize: AgenticReview → AwaitingAdmin (clean only).
Cheat / suspicious → immediate Score(0) (not admin-eligible).
Human role is selecting 1 or 2 winner harnesses per round via
POST /v1/admin/rounds/{id}/winners, or rejecting candidates via
POST /v1/admin/rounds/{id}/reject with a miner-visible reason
(no prompt approval, no page-pair Elo on the leaf path). Annotate endpoints
are deprecated / unused for scoring. Prompt bank bank_v1.json is fully
automatic — no human prompt validation.
Clean runs stamp awaiting_admin_epoch (chain epoch) when they enter
awaiting_admin. If still unscored when
current_epoch - awaiting_admin_epoch >= 5, the sweeper auto-rejects the run
(rejected, Score(0), reject_reason explaining the timeout) and sets
gating rejected. The miner must register a new UID (hotkey may leave and
re-enter the metagraph) before another submission is accepted.
Shared verifier: challenge-agentic (tools + challenge-ast + pages /
sanitize_report; OpenRouter when keyed, SimAgent in CI). Fail-closed:
unparseable verdict → NoScore(ChallengeInternal).
The review itself runs in a one-shot Docker container (same hardening pattern
as the sandbox: ReadonlyRootfs, CapDrop, no-new-privileges:true, uid
65532) built from deploy/Dockerfile target design-review
(challenge-agentic + challenge-ast). The container mounts the submitted
agent and the most-similar harness (_similar/) read-only; the LLM may
use the sandboxed run_command tool (scrubbed child env, cwd-pinned, 15s
cap, procfs + review-secrets paths denied) for diffs / grep / AST probes.
AGENTIC_ENABLE_RUN_COMMAND=1 stays on in prod (essential for review
quality). The OpenRouter key is file-mounted (OPENROUTER_API_KEY_FILE under
/run/review-secrets) and is never placed in the container's process
environ — Linux /proc/<pid>/environ is a boot-time snapshot and cannot be
scrubbed. DESIGN_REVIEW_BACKEND=inline keeps the legacy in-process path for
local/CI only.
Before any LLM call the orchestrator scores the candidate against the recent
harness corpus (byte hash + AST fingerprint). A byte/AST copy
(similarity ≥ 9500 bps) of a harness with strictly earlier created_at
→ run status rejected (terminal, Score(0), gating rejected) and the
LLM review is skipped. Unknown timestamps (baseline, legacy rows) fall
through to the LLM. Starting from the published miner baseline is never a
cheat signal (baseline-zeroing fix); copying another miner's harness is.
Corpus rule (both the gate and the LLM review): the comparison corpus is
other hotkeys' and same-coldkey prior art only — entries owned by the
candidate's own miner_hotkey or miner_coldkey are excluded, and so is
anything created at or after the candidate. After 1-max gating a miner iterates
via a new hotkey under the same coldkey; those revisions must not be treated as
cross-miner copies. Selection lives in one place,
crates/design-challenge/src/corpus.rs,
so the gate and the review can never disagree.
Internet + PyPI via egress, external APIs / MCP servers at run time, Mobbin / Dribbble / design refs, image generation, and UI libraries are allowed when the output is substantially transformed. Network use itself is never a cheat signal; copying another miner's harness or scrape-cloning a real site is.
| Code / pattern | Meaning |
|---|---|
near_identical_harness_copy |
Near-identical harness vs corpus (AST + LLM) |
trivial_republish_wrapper |
Thin wrapper republishing another miner's HTML |
scraped_site_clone |
Fetch + republish identifiable real site without substance |
sanitize_bypass |
Sanitize bypass / JS exfil / phishing reinjection |
obfuscation_to_hide_copy |
Obfuscation whose only purpose is hiding a copy |
suspicious → also Score(0) (same policy as Prism); rationale stored for admin.
Admin still picks 1 or 2 winner harnesses per round; each round win is
one point. The leaf projection uses a rolling window of the last
SCORING_WINDOW_ROUNDS = 10 rounds (replaces the v2 daily ≥2-wins rule):
| Situation | Leaf |
|---|---|
Miner with p window points (clean) |
Score(SCORE_MAX × p / total_window_points) — proportional share, integer floor |
| Miner without window wins | Score(0) |
| Cheat / suspicious / copy-gate rejected | Score(0) (wins excluded from the pool) |
| Round timeout, no winners set | no new points; window projection unchanged |
| No harness | NoScore(NotAttempted) |
| Agentic / infra failure (retry budget spent) | NoScore(ChallengeInternal) |
Leaf emit (scores_for_epoch) reads ratings from the latest scored round
with round.epoch ≤ target only — that row set is the rolling-window
projection written by award_round. Do not carry forward a miner's older
SCORE_MAX after they leave the window (per-miner history walk is a bug).
Proportional share uses integer floor division; the remainder is unassigned.
After round close: eliminate the bottom 20% of rated miners
(ELIMINATION_BOTTOM_BPS = 2000), at least 1 miner when the set is non-empty.
eliminated_until_round = round + 10 (ELIMINATION_COOLDOWN_ROUNDS = 10 → 1 day).
During cooldown: no new sandbox runs, no pairing — but D24 still requires a leaf:
emit Score(0). Silence is a bug.
Expected set E = all metagraph hotkeys for the pinned epoch (policy
all_metagraph_hotkeys). Leaf emit uses challenge-common::emit_signed_leaf_set:
- Exactly one signed leaf per
h ∈ E - Refuses subset and superset — Silence is a bug
- Emit at round close (scored) and near each epoch boundary via
POST /v1/weights/raw(Orchestrator::run_emitterfillsNotAttemptedwhen no admin award fired, so D24 seals keep advancing under 50/50 emission shares)
Absence codes used on this path include NotAttempted, Timeout,
InvalidResponse, MinerError, RateLimited, ChallengeInternal (bundle enum).
| Secret | Mounted where | Notes |
|---|---|---|
design_sk |
design-challenge only |
Signs leaves; never in sandbox/proxy |
| OpenRouter API key | design-egress-proxy only |
Injected on LLM allowlist path |
| Admin bearer tokens (winners API) | hashed in challenge config | Raw tokens in deploy/secrets/design/annotator_tokens (optional override DESIGN_ADMIN_TOKENS_FILE) |
| OpenRouter (agentic) | design-challenge |
Optional; missing key → SimAgent (CI/local only; never host Sim in staging/prod) |
Challenge signing key is never in miner harness, sandbox env, or gateway DB. Gateway is routing only (D18/D23).
| Service | Port | Image target |
|---|---|---|
design-challenge |
8093 |
design-challenge |
design-egress-proxy |
internal | design-egress-proxy |
| sandbox runtime | n/a | design-runtime (Python pin) |
Network: design-sandbox-egress (internal: true). Volume: design-artifacts.
Prod pins are digest-only — :latest forbidden. Rollable with
prism-challenge via updater ROLLABLE_SERVICES once deploy wiring lands.
Local health probe: http://127.0.0.1:28093/health (see
runbooks/local-testnet-e2e.md).
Proxied at /challenge/design/* → :8093.
Subnet frontends should poll (default hint poll_hint_ms = 1000); SSE is not required.
Stage journal (design_stage_event): every transition writes queued → installing →
running → sanitizing → agentic_review → awaiting_admin | scored | failed.
Harness stdout/stderr is appended as stage = "log" events with
detail.{phase,stream,seq,text} (install + run; truncated at 64 KiB per chunk).
| Route | Purpose |
|---|---|
POST /v1/harness |
Submit harness JSON, zip_base64, or application/zip (idempotent by digest); optional env_vars; returns run_ids + poll paths |
GET /v1/harness/{id} |
Harness detail |
GET /v1/harness?miner= |
List by miner |
GET /v1/quota/{hotkey} |
Daily quota remaining |
GET /v1/miners/{hotkey} |
Per-miner harnesses, runs, quota, rating |
GET /v1/prompts |
Prompt set descriptor |
GET /v1/rounds |
Round list |
GET /v1/runs/{id} |
Run detail (stage, scores, pages summary, errors) |
GET /v1/runs/{id}/events |
Append-only stage events |
GET /v1/runs/{id}/logs |
Harness logs (?since= cursor, optional ?tail=) |
Produced HTML is never served; the viewer exposes captured PNG screenshots only (see §6).
| Route | Purpose |
|---|---|
GET /v1/runs/{id}/pages |
Page metadata list (path, bytes, sha256) |
GET /v1/view/{id}/{page} |
PNG screenshots only (index.png); .html/bare page → 410 Gone |
GET /v1/runs/{id}/bundle.json |
410 Gone — no longer embeds produced HTML |
Admin routes are not exposed via gateway (/challenge/design/v1/admin/*
returns 403). Operators hit design-challenge:8093 on the master host
(SSH/VPC). Bearer tokens still required.
| Route | Purpose |
|---|---|
GET /v1/admin/rounds/{id}/candidates |
Clean awaiting_admin runs (pages + verdict) |
POST /v1/admin/rounds/{id}/winners |
Body { "harness_ids": ["…"] } length 1 or 2; awards + emits leaves |
POST /v1/admin/rounds/{id}/reject |
Body { "harness_ids": ["…"], "reason": "…" }; terminal rejected + miner-visible reject_reason on GET /v1/runs/{id}; gating closed until UID leave |
POST /v1/admin/rounds/current/requeue |
Same enqueue path as the round loop: schedule all active harnesses into the current open round (ops escape hatch / restart; idempotent per harness; quota-blocked harnesses reported under skipped) |
GET /v1/rounds/{id}/leaderboard |
Round ratings |
| Route | Purpose |
|---|---|
GET /v1/annotate/next?annotator= |
Legacy pair fetch |
POST /v1/annotate |
Legacy vote |
| Route | Purpose |
|---|---|
GET /health |
Liveness |
GET /v1/status |
Backend mode, epoch, queues |
GET /v1/stats |
Aggregate queue + round clock + digest |
GET /v1/dashboard |
One-shot UI JSON (status, leaderboards, recent runs) |
GET /v1/jobs |
Active/recent jobs |
POST /v1/runs/{id}/retry |
Operator retry |
| Crate | Role |
|---|---|
design-challenge-task |
Identity, domains, quotas, round math |
design-harness |
Bundle contract + embedded Python harness/SDK |
design-prompts |
Pinned prompt bank + deterministic weighted selection |
design-sandbox |
Two-phase Docker + SimSandbox |
design-sanitize |
HTML/CSS sanitize + viewer headers |
design-store |
DesignStore trait, memory + DB adapter (design_rating table) |
design-egress-proxy |
Open egress proxy (internal blocklist) + budgeted LLM path |
design-http |
Miner/viewer/admin winners/stats HTTP API |
design-challenge |
Orchestrator, agentic, scoring, leaf emit |
challenge-agentic |
Shared OpenRouter/Sim anti-cheat verifier |
challenge-ast |
Python AST fingerprint + similarity |
bins/design-challenge |
Operator binary :8093 |
bins/design-egress-proxy |
Proxy binary |
Shared: challenge-common (exact-E), challenge-keys, docker-engine.
- Miner guide:
external-miner/ - Emission ceremony:
runbooks/design-enable-and-emission.md - Prism (sibling challenge):
PRISM.md - Architecture map:
ARCHITECTURE.md