Views
No views yet
1flowchart TD
2 subgraph miner["Miner (no GPU)"]
3 gen["generator.py<br/>(DataGenerator)"]
4 upload["push to Hippius Hub registry<br/>(OCI) → repo@digest"]
5 commit["commit on-chain pointer<br/>metro-v1:gen:hippius:repo@digest"]
6 gen --> upload --> commit
7 end
8
9 subgraph trainer["Trainer: owner-operated (the GPU boundary)"]
10 resolve["resolve commitments before the<br/>24h epoch cutoff → king + field"]
11 seeds["derive one shared RoundSeeds<br/>from epoch-boundary block hash<br/>(generation_seed + training_seed)"]
12 heat["HEAT: train every challenger<br/>~30min (primary size) → screen<br/>→ top finalist"]
13 trainK["FINAL: train king + finalist<br/>from random init at EVERY size<br/>(Toto2-4M, Toto2-22M)"]
14 upK["push ckpts → Hippius Hub registry<br/>logs/metrics → Hippius S3"]
15 manifest["sign + publish TrainingManifest<br/>to Hippius S3 (size-tagged ckpt refs + digests)"]
16 resolve --> seeds --> heat --> trainK --> upK --> manifest
17 end
18
19 subgraph validator["Validator (eval GPU)"]
20 gate["verify signature +<br/>matching contract / base-arch digests<br/>(controlled-experiment gate)"]
21 eval["pull king + finalist ckpts per size →<br/>score on shared held-out windows<br/>(CRPS/MWSQL + MASE)"]
22 koth["paired-bootstrap LCB of<br/>geomean(CRPS, MASE) POOLED across sizes,<br/>finalist vs king → one KOTH verdict"]
23 weights["equal-share weights<br/>(king + recent kings)"]
24 gate --> eval --> koth --> weights
25 end
26
27 commit -->|on-chain| resolve
28 manifest -->|S3 manifest + registry ckpts| gate
29
30 classDef invariant fill:#fff3cd,stroke:#d39e00,color:#5c4400;
31 class seeds,gate invariant;The highlighted boxes are where the controlled experiment lives: the trainer reuses oneRoundSeedsfor every run in the round, and the validator's digest gate rejects any manifest where king and challenger didn't share that contract. Details below.
[round] epoch_blocks): the
trainer runs exactly one round per day, so the king is trained once per day and
the whole day's trainings share one RoundSeeds (identical random init). Only
generators whose on-chain pointer revealed strictly before the epoch boundary
compete in that round — deploy defaults to a timed reveal targeting just before
the boundary (docs/MINER.md §5a), and a reveal that lands late rolls into the
next one. Each round has two stages: a cheap
heat trains every eligible challenger for [round] heat_train_hours (~30min,
primary size) and the owner screens them down to the top [round] finalists; the
final then trains the king and the surviving finalist to the full
[training] target_train_hours (~3h) at every configured size (the 4M primary
plus each [[training.sizes]], e.g. 22M).chain.toml [training], with per-size overrides in [[training.sizes]]). Each
model trains for a fixed wall-clock budget (~3h on the owner's reference GPU),
enforced as a fixed token count (hours × reference throughput) so king and
challenger get identical compute. A raw timer would let a generator win by
emitting cheap-to-step data rather than better data, and wouldn't reproduce on a
re-derived audit run.dethrone_cp round(s) by a
confidence-bounded margin (paired bootstrap LCB clears the win margin). The
shipped chain.toml sets dethrone_cp = 1 with a flat, no-tenure margin
(win_margin_start == win_margin_end, margin_warmup_rounds = 0), so a single
decisive round dethrones and every king is equally challengeable; raise
dethrone_cp and re-enable the warmup for the sticky, tenure-weighted variant.
Weights are split equally across the current king plus up to reward_prior_kings
recent distinct kings still registered (burning to burn_uid if none are), with
reward_prior_kings = 0 collapsing to pure winner-take-all.| role | package | needs GPU | needs chain |
|---|---|---|---|
| miner | cascade.miner | no | to deploy |
| trainer (owner) | cascade.trainer | yes | to read king / sign manifest |
| validator | cascade.validator | yes (eval) | to set weights |
cascade/
interface/ miner-facing contract (DataGenerator ABC, output checks, static guard)
eval/ scoring math: CRPS (MWSQL), MASE, paired bootstrap, KOTH decision
trainer/ owner GPU service: corpus build, fixed contract, train+upload, manifest
validator/ manifest gate, checkpoint evaluator, KOTH state machine, weights
miner/ miner CLI: verify, deploy (push to Hippius Hub registry + commit)
shared/ config loader, Hippius Hub registry/S3, chain client, manifest schema
website/ the public dashboard ("notebook"): a self-contained index.html
docs/
ARCHITECTURE.md end-to-end flow, trust model, the controlled-experiment invariant
MINER.md run a miner end to end: fork → verify → register → deploy
VALIDATOR.md run a validator end to end: register → configure → score → set weights
INTERFACE.md the DataGenerator submission contract for miners
AUDIT.md verifying published rounds with cascade-audit (receipts, tiers)
scripts/
example_generator/ a forkable reference generator (also a test fixture)
publish_website.py upload the dashboard to the manifest bucket (public-read)
scrape_kings.py archive every throne-holding generator to a private R2 bucketuv sync / pip install -e .:cascade verify <repo_dir>: runs every check the trainer runs (layout,
static guard, hash-locked deps, and the determinism check: your generator
must produce a byte-identical corpus at a fixed seed).cascade score <repo_dir> --pool-dir <held-out>: train the fixed model on your
generator at the cheap heat budget and score it locally, offline (no chain, no
wait) — the fast iteration loop. Needs the .[train] extra.cascade deploy <repo_dir> --hub-repo <ns/name> --wallet-name ... --wallet-hotkey ...:
verifies the local generator, pushes it to the Hippius Hub registry (OCI),
and commits metro-v1:gen:hippius:<repo>@<digest> on-chain (the OCI digest pins
the content — no git SHA).cascade fetch king (or a <uid> / <hotkey> / <repo>@<digest>): downloads
a competitor's on-chain generator to a local dir to inspect or fork. Generators
are public by design — you win by improving on the visible best. Read-only, no
wallet.cascade round: a live countdown dashboard to the next round — current block,
epoch progress, and the submission deadline (commit strictly before the epoch
boundary to enter that round). --once for a single snapshot. Read-only, no
wallet.cascade-trainer --trainer cascade.trainer.toto2_trainer:Toto2Trainer:
the owner training service (--offline for a config/seed smoke); the reference
Toto2-4M backend lives in cascade.trainer.toto2_trainer. Add
--remote-hosts hosts.toml to train the king and challenger in parallel on
separate SSH GPU pods (Lium/Targon); see scripts/remote_hosts.example.toml.cascade-train-worker: the per-pod worker the remote dispatch runs (trains
one role, uploads its checkpoint, prints a receipt — no wallet on the pod).cascade-validator: the validator loop (--offline for a state smoke).cascade-audit latest / cascade-audit round <id>: third-party verification
of a published round receipt — re-derives seeds, digests, the KOTH verdict,
and (at --tier 1) each generator's corpus, with a nonzero exit on any
mismatch (CI-usable). No wallet or GPU needed for tiers 0–1; see
docs/AUDIT.md.repo@digest), manifests + training logs on Hippius
S3. Install the extra (pip install -e '.[hippius]') and set the env
credentials (HIPPIUS_S3_ACCESS_KEY / HIPPIUS_S3_SECRET_KEY, and a Hub token
HIPPIUS_HUB_TOKEN or HIPPIUS_HUB_USERNAME + HIPPIUS_HUB_PASSWORD).RoundReceipt to the manifest bucket — the full public
record of the round (chain context, the trainer's manifest verbatim, the
participant set, every per-window score, the KOTH verdict, and the weight
vector), so a third party can re-derive the owner's work without trusting it.
The layout mirrors the manifests:s3://<manifest_bucket>/manifests/round-<id>.json the trainer's signed manifest
s3://<manifest_bucket>/manifests/latest.json pointer to the newest manifest
s3://<manifest_bucket>/receipts/<hotkey>/round-<id>.json a validator's signed receipt
s3://<manifest_bucket>/receipts/<hotkey>/latest.json that validator's newest receipt
s3://<manifest_bucket>/receipts/latest.json shared pointer to the newest receipt
s3://<manifest_bucket>/receipts/index.json rolling round summary (dashboard)cascade/website/index.html renders the live
king-of-the-hill state — the reigning king generator, the reign chain, the
per-round KOTH verdicts, and geomean(CRPS·MASE) skill over time — in a
paper-notebook style. It is a static page that reads only the public-read
receipts above: receipts/latest.json for the current round's detail and
receipts/index.json for history. The validator maintains that index (a
rolling window of compact per-round summaries with a pointer back to each
signed receipt) alongside every receipt it publishes — presentational only, so
a stale index never affects weights, and audit trust still flows through the
signed per-round receipts. With several validators live, each writes only under
its own receipts/<hotkey>/ prefix (no clobbering); the shared index carries
one entry per (round, validator) and the dashboard shows one row per round. Serve the page from the same bucket with
python scripts/publish_website.py (needs the HIPPIUS_S3_* credentials); it
then lives at <s3_endpoint>/<manifest_bucket>/index.html.<id> is the round id (the base seed derived from the epoch-boundary block
hash). A round the validator rejected still gets a receipt
("status": "rejected") carrying the gate's reason. Verify one with
cascade-audit latest — see docs/AUDIT.md.receipts/index.json. python scripts/scrape_kings.py closes that gap:
it reads that index, and for every generator that has ever held the throne
fetches its code from the Hub and saves it — packed to a deterministic tar — to
a private R2 bucket ([storage] king_archive_bucket), plus a
kings/index.json "db" that links each king to its archived object (with the
owning hotkey/uid and the rounds it reigned). The archive is content-addressed
and append-only — a king already saved is never re-fetched — so it's cheap to
run on a schedule (.github/workflows/scrape-kings.yml runs it daily). Endpoint
and credentials default to the same R2 account chain.toml already uses for the
manifest/receipt backup (BACKUP_S3_*), so no new account is needed; keep the
bucket private. See cascade.shared.king_archive.chain.toml ships with mainnet values baked in (netuid 91, the L40S GPU pin,
the worker-image digest, pool_bucket). The remaining operator-specific values —
trainer_hotkey, commit_floor_block, the launch-commit image re-pin, and the
gift-gate mode — are set on the deployment box, not in the shipped chain.toml.1pip install -e . # core: numpy + scipy only
2pip install -e '.[dev]' # + pytest/ruff/hypothesis
3python -m pytest tests/unit -q # CPU tests, no torch/HF/chain needed.[train] (torch/transformers for the trainer + validator evaluator),
.[hippius] (Hippius Hub registry + S3 + huggingface_hub), and .[chain]
(bittensor).cascade.trainer.contract.BaseTrainer protocol (the GPU boundary). A runnable
reference implementation ships in cascade.trainer.toto2_trainer (a causal
patch transformer with a 9-quantile pinball head, trained from random init under
the chain.toml [training] recipe); it needs a GPU to validate end-to-end, so
run it on your reference box before pinning base_arch_digest. Everything above
that boundary is numpy/CPU and tested. See docs/ARCHITECTURE.md.