From c6d071b3585756554ed743fbd2778454ab8422e2 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 5 Sep 2026 08:57:50 +0000 Subject: [PATCH 1/2] docs(readme): rewrite root readme and drop marketing banner Replace the centered badge/banner hero with an English, scannable control-plane README. Link in-repo miner and operator docs instead of inlining eval digests. Co-authored-by: Mathis --- README.md | 193 +++++++++++++++++++++++++++++++++++----------- assets/banner.jpg | Bin 38316 -> 0 bytes 2 files changed, 148 insertions(+), 45 deletions(-) delete mode 100644 assets/banner.jpg diff --git a/README.md b/README.md index 62efacd24..bb35c271d 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,171 @@ -
- # Cortex -**Bittensor subnet control plane (Rust).** - [![CI](https://github.com/CortexLM/cortex/actions/workflows/ci.yml/badge.svg)](https://github.com/CortexLM/cortex/actions/workflows/ci.yml) -[![License](https://img.shields.io/github/license/CortexLM/cortex)](https://github.com/CortexLM/cortex/blob/main/LICENSE) -[![Bittensor](https://img.shields.io/badge/Bittensor-subnet-black.svg)](https://bittensor.com/) +[![License](https://img.shields.io/github/license/CortexLM/cortex)](LICENSE) + +Cortex is the Rust control plane for [Bittensor](https://bittensor.com/) subnet **100** (`CortexLM/cortex`). It is the software that accepts miner work over HTTP, scores the two live challenges on the master host, seals an epoch weight bundle, and lets validators verify that bundle before they `set_weights` on-chain. -Whitepaper +If you want to **mine**, install `ctx` and start at [docs/external-miner/](docs/external-miner/README.md). If you want to **validate**, read [How to validate](docs/external-miner/validators.md). If you want to **change this repo**, see [Contributing](#contributing). -Cortex Banner +## What it is -
+This repo is the subnet control plane: the processes that take miner work, score it, seal weights, and submit them on-chain. -Cortex is the control plane for a Bittensor subnet with two live challenges. -The master host runs every live challenge service and the gateway. Miners -submit over HTTP (`ctx`). The gateway seals an epoch weight bundle. -Validators pull that bundle, verify it, and `set_weights` on-chain. They do -not run evals. +- **Gateway** (master only) — TLS, reverse proxy, registry, and the seal/serve path for epoch weights. +- **Challenge services** (master only) — `bounty-challenge` and `proof-challenge`. These score miner work. Validators never re-run evals. +- **Validator** — fetches the sealed bundle, checks it against owner-signed trust roots on disk, and submits weights on-chain. +- **`ctx`** — the miner CLI. Same HTTP routes as `curl`. -| Challenge | id | What miners improve | Default emission | -|-----------|-----|---------------------|------------------| -| **Bounty** | `bounty` | Bug hunters report defects across cortex.foundation and Cortex applications (product surfaces) so continuous production service stays low-defect for clients | 2000 bps | -| **Proof** | `proof` | Reproducible experiments (claim + code + FLOPs) against operator-published research topics; digest-pinned RLM judge | 8000 bps | +Live emission is **Bounty 2000 bps / Proof 8000 bps** (20/80). The two shares sum to 10000. Older products (`relearn`, `relearn-image`, `relearn-agent`, `relearn-mm`, `design`, `prism`) have no trust-root row and earn nothing. -Live emission is **bounty 2000 / proof 8000** (20/80). The sum is 10000. -Proof's eval image is pinned at -`ghcr.io/cortexlm/proof-eval@sha256:78b614a1f51ce5dd80076c4e343a2b31b85d6c36025e02836cb83929867e7009`. -An empty digest would still **503**. `relearn`, `relearn-image`, -`relearn-agent`, `relearn-mm`, `design`, and `prism` are **off**: no -trust-root row, no emission. +Some environment variables and host paths still spell `BASE_*`. That is leftover naming from an earlier product identity, not a second stack. See [docs/NAMING.md](docs/NAMING.md). -Bounty pays precision times severity; an unpriced `valid` row is not -creditable, and the triage-noise ratio stays off the visible score. Proof -scores WTA or discovery over currently `open` operator-published -topics (sum of per-topic masses); empty `eval_image_digest` or an empty open set fails closed (`503`). -Missing evidence fails closed rather than passing. +## Why it is built this way -Some env vars and host paths still spell `BASE_*`. That is leftover naming, -not a second product. +Subnet scoring is centralized on the owner host so miners have one public HTTP surface. Consensus is **not** “every validator re-runs every experiment.” Validators recompute the weight vector from a signed, merkle-rooted epoch bundle and from **local** owner-signed files (`config/challenges.toml`, `config/measurements.toml`). Challenge keys never come from gateway HTTP. -## Mine +Missing evidence, an empty Proof eval digest, an empty open-topic set, or an unreadable Bounty score feed **fail closed** (`503` / `NoScore`) instead of inventing a verdict. `GET /v1/weights/latest` with no sealed bundle is a burn vector (`sealed: false`, uid 0 = 100%), not a stale last-known-good. -Miners and validators talk to one public gateway: -**`https://network.cortex.foundation`**. Install the subnet CLI: +## Quickstart (miners) + +Miners and validators talk to the public gateway at +**https://network.cortex.foundation**. ```bash curl -fsSL https://raw.githubusercontent.com/CortexLM/cortex/main/scripts/install-ctx.sh | sh ctx challenges # the two live challenges and what they pay for -ctx status # can each challenge score right now, and is the epoch sealed +ctx status # can each challenge score right now, and is the epoch sealed +``` + +`ctx` lives in [`bins/ctx`](bins/ctx). A local stack uses `--gateway http://127.0.0.1:8080` (or whatever tunnel URL you printed). Never put a mnemonic or a challenge signing key in a miner client. + +| You want to | Command | Guide | +|-------------|----------|-------| +| File product/backend bugs | `ctx bounty pair` then `ctx bounty report` | [Bounty](docs/external-miner/bounty.md) | +| Reproduce a research topic | `ctx proof topics` then `ctx proof submit` | [Proof](docs/external-miner/proof.md) | +| Debug a 503 / install issue | `ctx status` | [Troubleshoot](docs/external-miner/troubleshoot.md) | + +Check `can_score` before you spend GPU time or Lium rent. A host that cannot score stores nothing and rents nothing. + +## Architecture + +```text + Miners (ctx / curl) + │ HTTP submit + ▼ + ┌─────────────────────────────────────┐ + │ Master host │ + │ postgres · gateway │ + │ bounty-challenge · proof-challenge │ + └──────────────────┬────────────────────┘ + │ GET /v1/weights/latest + │ (sealed epoch bundle) + ▼ + Validator hosts + local trust roots on disk + │ + ▼ + set_weights (CRV4) +``` + +One epoch, short form: + +1. Challenge services sign leaves for the expected miner set. +2. The gateway seals `EpochBundleV1` (merkle root + signature). +3. Validators fetch latest, verify against the local trust root, cross-check peers, recompute, then submit. + +The map, process list, and what this architecture does **not** claim: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md). Byte layout: [docs/BUNDLE_SPEC.md](docs/BUNDLE_SPEC.md). + +## Live challenges + +### Bounty (`bounty`, 2000 bps) + +Pair a Bittensor hotkey to a **dedicated** Cortex Chat mining account, then file real bugs on Cortex product and backend surfaces. Operators adjudicate (`valid` / `already_fixed_not_prod` / `invalid_malicious` / `duplicate`). Pay is precision times severity; an unpriced `valid` row is not creditable, and triage noise stays off the visible score. + +Scoring **reads** the CortexLM/backend public JSON feed. This repo does not serve a public leaderboard. If that feed is unreadable, reports answer **503** and the share pays nobody. + +Guide: [docs/external-miner/bounty.md](docs/external-miner/bounty.md) · operator spec: [docs/BOUNTY.md](docs/BOUNTY.md) + +### Proof (`proof`, 8000 bps) + +Submit **claim + code + FLOPs + artifact** against an operator-published `topic_id`. Topics are signed documents, not a catalog in git. Each open topic pays `wta` (winner takes that topic's mass) or `discovery` (pass floor + novelty). Your paid score is the **sum** of per-topic masses, not a mean of binary lattices. + +The judge is a digest-pinned eval image plus a live `InferenceOffer`. The pin lives in [`config/proof-pin.toml`](config/proof-pin.toml) — do not invent a digest. Empty digest, unwired harvest, unsealed baseline, or zero open topics → **503**. Proof miners pay Lium (`LIUM_API_KEY` / `X-Lium-Api-Key`); `ctx` forwards the key and never prints it. + +`ctx proof topics` lists currently open topics and never leaks holdout records. + +Guide: [docs/external-miner/proof.md](docs/external-miner/proof.md) · operator spec: [docs/PROOF.md](docs/PROOF.md) + +## Validators + +Validators do not run Bounty adjudication or Proof harvest. They: + +1. Pull `GET /v1/weights/latest` from the master gateway. +2. Verify signatures, completeness, and the owner trust root on **local disk**. +3. `set_weights` on-chain (CRV4 timelock when enabled). + +Do not submit an unsealed burn vector, and do not submit a persisted last-known-good seal while latest is unsealed. Runbook: [docs/external-miner/validators.md](docs/external-miner/validators.md). Compose role: [`deploy/compose/role-validator.yml`](deploy/compose/role-validator.yml). + +## Repository layout + +| Path | Role | +|------|--------| +| [`bins/`](bins/) | Runnable processes: `gateway`, `validator`, `ctx`, challenge services, `updater` | +| [`crates/`](crates/) | Shared libraries (bundle, aggregate, trustroot, chain, …) | +| [`xtask/`](xtask/) | Repo gates (`loc-cap`, `spec-check`, `external-docs-check`, …) | +| [`deploy/`](deploy/) | Compose matrix, Terraform, digest pins, remote deploy | +| [`docs/`](docs/) | Architecture, frozen specs, runbooks, miner guides | +| [`config/`](config/) | Non-secret configuration (trust-root TOML, Proof pin) | + +Working branch is **`main`**. Production ships from annotated tags `v*.*.*` cut on `main`. + +## Develop (this repo) + +Rust **1.96.0** via [`rust-toolchain.toml`](rust-toolchain.toml). `unsafe_code` is forbidden; `unwrap` / `expect` stay in tests. + +```bash +cargo fmt --all -- --check +cargo clippy --workspace --all-targets -- -D warnings +cargo test --workspace +cargo deny check +cargo run -p xtask -- loc-cap +cargo run -p xtask -- consensus-lint +cargo run -p xtask -- spec-check +cargo run -p xtask -- design-check +cargo run -p xtask -- external-docs-check ``` -`ctx` ([`bins/ctx`](bins/ctx)) submits to the two live challenges and handles -Bounty pairing. `curl` works against the same routes. +Local full-subnet smoke (Docker Compose, testnet 541, optional tunnel): + +```bash +./deploy/scripts/materialize-env.sh +./deploy/scripts/local-e2e.sh --smoke +``` + +Details: [docs/runbooks/local-testnet-e2e.md](docs/runbooks/local-testnet-e2e.md) and [deploy/README.md](deploy/README.md). Do not commit `deploy/env/*.env`, wallets, or age identities. + +## Contributing + +Read [CONTRIBUTING.md](CONTRIBUTING.md) and [AGENTS.md](AGENTS.md) before you open a PR. + +- Target **`main`**. Subject: `type(scope): summary` (lowercase, ≤72 chars). +- Frozen specs (`docs/BUNDLE_SPEC.md`, `docs/DESIGN_CHALLENGE.md`) are pinned by xtask. Do not rewrite incentive or consensus semantics in a drive-by. +- Do not rename `BASE_*` env vars, `/opt/base` paths, or `base-*-v1` domain tags. Those strings are measured into live droplets and miner CVMs. +- PRs need a [Greptile](https://greptile.com) review (`.greptile/`). If the bot is silent, comment `@greptileai review`. +- Security reports go through [SECURITY.md](SECURITY.md), not a public issue. -| Challenge | Start with | Guide | -|-----------|-----------|-------| -| Bounty | `ctx bounty pair` | **[How to mine — Bounty](docs/external-miner/bounty.md)** | -| Proof | `ctx proof submit` | **[How to mine — Proof](docs/external-miner/proof.md)** | +## Documentation -Start at **[docs/external-miner/](docs/external-miner/README.md)** for the -A→Z, and **[How to validate](docs/external-miner/validators.md)** if you run a -validator. +| Doc | Audience | +|-----|----------| +| [docs/external-miner/README.md](docs/external-miner/README.md) | Miners (A→Z) | +| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Process topology | +| [docs/COMPLETENESS.md](docs/COMPLETENESS.md) | What is actually wired | +| [docs/THREAT_MODEL.md](docs/THREAT_MODEL.md) | What is claimed, and what is not | +| [docs/OPERATOR_SECURITY.md](docs/OPERATOR_SECURITY.md) | Operator checklist | +| [docs/runbooks/](docs/runbooks/) | Staging, local e2e, rotation, failover | +| [whitepaper.pdf](whitepaper.pdf) | Whitepaper | +| [SUPPORT.md](SUPPORT.md) | How to get help | -Apache License 2.0 — see [LICENSE](./LICENSE). +Apache License 2.0 — see [LICENSE](LICENSE). diff --git a/assets/banner.jpg b/assets/banner.jpg deleted file mode 100644 index 375c3f21dc4b81762972be9d37a22db6a1a64b06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38316 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 Date: Sat, 5 Sep 2026 09:00:54 +0000 Subject: [PATCH 2/2] docs(readme): add features grid and mine/validate sections Restructure the root README around a one-line value prop, a capability table, and Mine / Validate / Architecture / Docs / Contributing / License. Co-authored-by: Mathis --- README.md | 170 ++++++++++++++++++++++++------------------------------ 1 file changed, 74 insertions(+), 96 deletions(-) diff --git a/README.md b/README.md index bb35c271d..f102a29c7 100644 --- a/README.md +++ b/README.md @@ -3,50 +3,65 @@ [![CI](https://github.com/CortexLM/cortex/actions/workflows/ci.yml/badge.svg)](https://github.com/CortexLM/cortex/actions/workflows/ci.yml) [![License](https://img.shields.io/github/license/CortexLM/cortex)](LICENSE) -Cortex is the Rust control plane for [Bittensor](https://bittensor.com/) subnet **100** (`CortexLM/cortex`). It is the software that accepts miner work over HTTP, scores the two live challenges on the master host, seals an epoch weight bundle, and lets validators verify that bundle before they `set_weights` on-chain. +Rust control plane for [Bittensor](https://bittensor.com/) subnet **100**: miners submit over HTTP, the master scores two live challenges, validators verify a sealed weight bundle and `set_weights`. -If you want to **mine**, install `ctx` and start at [docs/external-miner/](docs/external-miner/README.md). If you want to **validate**, read [How to validate](docs/external-miner/validators.md). If you want to **change this repo**, see [Contributing](#contributing). +## Features -## What it is +| Capability | Detail | +|---|---| +| **Two live challenges** | **Bounty** (`bounty`, 2000 bps) and **Proof** (`proof`, 8000 bps). Sum is 10000. `relearn`, `relearn-image`, `relearn-agent`, `relearn-mm`, `design`, and `prism` are off. | +| **One public gateway** | [https://network.cortex.foundation](https://network.cortex.foundation) — `ctx` or `curl`. | +| **Master-only scoring** | Gateway + `bounty-challenge` + `proof-challenge` run on the owner host. Validators do not re-run evals. | +| **Fail-closed scoring** | Empty Proof eval digest, no open topic, or an unreadable Bounty feed answers **503** instead of inventing a verdict. | +| **Sealed weights** | Gateway seals an epoch bundle. Validators check it against owner-signed files on disk, then submit (CRV4 when enabled). | -This repo is the subnet control plane: the processes that take miner work, score it, seal weights, and submit them on-chain. +Some env vars and host paths still spell `BASE_*`. That is leftover naming, not a second product. See [docs/NAMING.md](docs/NAMING.md). -- **Gateway** (master only) — TLS, reverse proxy, registry, and the seal/serve path for epoch weights. -- **Challenge services** (master only) — `bounty-challenge` and `proof-challenge`. These score miner work. Validators never re-run evals. -- **Validator** — fetches the sealed bundle, checks it against owner-signed trust roots on disk, and submits weights on-chain. -- **`ctx`** — the miner CLI. Same HTTP routes as `curl`. +## Quickstart -Live emission is **Bounty 2000 bps / Proof 8000 bps** (20/80). The two shares sum to 10000. Older products (`relearn`, `relearn-image`, `relearn-agent`, `relearn-mm`, `design`, `prism`) have no trust-root row and earn nothing. +```bash +curl -fsSL https://raw.githubusercontent.com/CortexLM/cortex/main/scripts/install-ctx.sh | sh -Some environment variables and host paths still spell `BASE_*`. That is leftover naming from an earlier product identity, not a second stack. See [docs/NAMING.md](docs/NAMING.md). +ctx challenges # the two live challenges and what they pay for +ctx status # can each challenge score right now, and is the epoch sealed +``` -## Why it is built this way +`ctx` lives in [`bins/ctx`](bins/ctx). A local stack uses `--gateway http://127.0.0.1:8080`. Never put a mnemonic or a challenge signing key in a miner client. Check `can_score` before you spend GPU time or Lium rent. -Subnet scoring is centralized on the owner host so miners have one public HTTP surface. Consensus is **not** “every validator re-runs every experiment.” Validators recompute the weight vector from a signed, merkle-rooted epoch bundle and from **local** owner-signed files (`config/challenges.toml`, `config/measurements.toml`). Challenge keys never come from gateway HTTP. +## Mine -Missing evidence, an empty Proof eval digest, an empty open-topic set, or an unreadable Bounty score feed **fail closed** (`503` / `NoScore`) instead of inventing a verdict. `GET /v1/weights/latest` with no sealed bundle is a burn vector (`sealed: false`, uid 0 = 100%), not a stale last-known-good. +| Challenge | id | Emission | Start with | Guide | +|-----------|-----|----------|------------|-------| +| **Bounty** | `bounty` | 2000 bps | `ctx bounty pair` then `ctx bounty report` | [How to mine — Bounty](docs/external-miner/bounty.md) | +| **Proof** | `proof` | 8000 bps | `ctx proof topics` then `ctx proof submit` | [How to mine — Proof](docs/external-miner/proof.md) | -## Quickstart (miners) +A→Z index: [docs/external-miner/](docs/external-miner/README.md). Install or 503 issues: [troubleshoot](docs/external-miner/troubleshoot.md). -Miners and validators talk to the public gateway at -**https://network.cortex.foundation**. +### Bounty -```bash -curl -fsSL https://raw.githubusercontent.com/CortexLM/cortex/main/scripts/install-ctx.sh | sh +Pair a Bittensor hotkey to a **dedicated** Cortex Chat mining account, then file real bugs on Cortex product and backend surfaces. Operators adjudicate (`valid` / `already_fixed_not_prod` / `invalid_malicious` / `duplicate`). Pay is precision times severity; an unpriced `valid` row is not creditable. -ctx challenges # the two live challenges and what they pay for -ctx status # can each challenge score right now, and is the epoch sealed -``` +Scoring **reads** the CortexLM/backend public JSON feed. This repo does not serve a public leaderboard. If that feed is unreadable, reports answer **503** and the share pays nobody. + +### Proof + +Submit **claim + code + FLOPs + artifact** against an operator-published `topic_id`. Topics are signed documents, not a catalog in git. Each open topic pays `wta` or `discovery`. Your paid score is the **sum** of per-topic masses. + +The judge is a digest-pinned eval image plus a live `InferenceOffer`. The pin is in [`config/proof-pin.toml`](config/proof-pin.toml) (`ghcr.io/cortexlm/proof-eval`, digest `sha256:78b614a1…`). Do not invent a digest. Empty digest, unwired harvest, unsealed baseline, or zero open topics → **503**. Proof miners pay Lium (`LIUM_API_KEY` / `X-Lium-Api-Key`); `ctx` forwards the key and never prints it. + +`ctx proof topics` never leaks holdout records. + +## Validate + +Validators pull the sealed bundle, verify it, and submit weights on-chain. They do not run Bounty adjudication or Proof harvest. -`ctx` lives in [`bins/ctx`](bins/ctx). A local stack uses `--gateway http://127.0.0.1:8080` (or whatever tunnel URL you printed). Never put a mnemonic or a challenge signing key in a miner client. +1. Pull `GET /v1/weights/latest` from the master gateway. +2. Verify signatures, completeness, and the owner trust root on **local disk** (`config/challenges.toml`, `config/measurements.toml`). +3. `set_weights` on-chain (CRV4 timelock when enabled). -| You want to | Command | Guide | -|-------------|----------|-------| -| File product/backend bugs | `ctx bounty pair` then `ctx bounty report` | [Bounty](docs/external-miner/bounty.md) | -| Reproduce a research topic | `ctx proof topics` then `ctx proof submit` | [Proof](docs/external-miner/proof.md) | -| Debug a 503 / install issue | `ctx status` | [Troubleshoot](docs/external-miner/troubleshoot.md) | +Do not submit an unsealed burn vector (`sealed: false`, uid 0 = 100%), and do not submit a persisted last-known-good seal while latest is unsealed. -Check `can_score` before you spend GPU time or Lium rent. A host that cannot score stores nothing and rents nothing. +Guide: [How to validate](docs/external-miner/validators.md) · compose role: [`deploy/compose/role-validator.yml`](deploy/compose/role-validator.yml). ## Architecture @@ -69,58 +84,38 @@ Check `can_score` before you spend GPU time or Lium rent. A host that cannot sco set_weights (CRV4) ``` -One epoch, short form: - -1. Challenge services sign leaves for the expected miner set. -2. The gateway seals `EpochBundleV1` (merkle root + signature). -3. Validators fetch latest, verify against the local trust root, cross-check peers, recompute, then submit. - -The map, process list, and what this architecture does **not** claim: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md). Byte layout: [docs/BUNDLE_SPEC.md](docs/BUNDLE_SPEC.md). - -## Live challenges - -### Bounty (`bounty`, 2000 bps) - -Pair a Bittensor hotkey to a **dedicated** Cortex Chat mining account, then file real bugs on Cortex product and backend surfaces. Operators adjudicate (`valid` / `already_fixed_not_prod` / `invalid_malicious` / `duplicate`). Pay is precision times severity; an unpriced `valid` row is not creditable, and triage noise stays off the visible score. - -Scoring **reads** the CortexLM/backend public JSON feed. This repo does not serve a public leaderboard. If that feed is unreadable, reports answer **503** and the share pays nobody. - -Guide: [docs/external-miner/bounty.md](docs/external-miner/bounty.md) · operator spec: [docs/BOUNTY.md](docs/BOUNTY.md) - -### Proof (`proof`, 8000 bps) - -Submit **claim + code + FLOPs + artifact** against an operator-published `topic_id`. Topics are signed documents, not a catalog in git. Each open topic pays `wta` (winner takes that topic's mass) or `discovery` (pass floor + novelty). Your paid score is the **sum** of per-topic masses, not a mean of binary lattices. - -The judge is a digest-pinned eval image plus a live `InferenceOffer`. The pin lives in [`config/proof-pin.toml`](config/proof-pin.toml) — do not invent a digest. Empty digest, unwired harvest, unsealed baseline, or zero open topics → **503**. Proof miners pay Lium (`LIUM_API_KEY` / `X-Lium-Api-Key`); `ctx` forwards the key and never prints it. - -`ctx proof topics` lists currently open topics and never leaks holdout records. - -Guide: [docs/external-miner/proof.md](docs/external-miner/proof.md) · operator spec: [docs/PROOF.md](docs/PROOF.md) +One epoch: challenge services sign leaves → the gateway seals `EpochBundleV1` → validators fetch, verify, recompute, and submit. -## Validators - -Validators do not run Bounty adjudication or Proof harvest. They: - -1. Pull `GET /v1/weights/latest` from the master gateway. -2. Verify signatures, completeness, and the owner trust root on **local disk**. -3. `set_weights` on-chain (CRV4 timelock when enabled). +| Path | Role | +|------|------| +| [`bins/`](bins/) | `gateway`, `validator`, `ctx`, challenge services, `updater` | +| [`crates/`](crates/) | Shared libraries (bundle, aggregate, trustroot, chain, …) | +| [`deploy/`](deploy/) | Compose matrix, Terraform, digest pins | +| [`config/`](config/) | Trust-root TOML, Proof pin | +| [`docs/`](docs/) | Specs, runbooks, miner guides | -Do not submit an unsealed burn vector, and do not submit a persisted last-known-good seal while latest is unsealed. Runbook: [docs/external-miner/validators.md](docs/external-miner/validators.md). Compose role: [`deploy/compose/role-validator.yml`](deploy/compose/role-validator.yml). +Full map: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md). Byte contract: [docs/BUNDLE_SPEC.md](docs/BUNDLE_SPEC.md). -## Repository layout +## Docs -| Path | Role | -|------|--------| -| [`bins/`](bins/) | Runnable processes: `gateway`, `validator`, `ctx`, challenge services, `updater` | -| [`crates/`](crates/) | Shared libraries (bundle, aggregate, trustroot, chain, …) | -| [`xtask/`](xtask/) | Repo gates (`loc-cap`, `spec-check`, `external-docs-check`, …) | -| [`deploy/`](deploy/) | Compose matrix, Terraform, digest pins, remote deploy | -| [`docs/`](docs/) | Architecture, frozen specs, runbooks, miner guides | -| [`config/`](config/) | Non-secret configuration (trust-root TOML, Proof pin) | +| Doc | Audience | +|-----|----------| +| [docs/external-miner/README.md](docs/external-miner/README.md) | Miners | +| [docs/external-miner/bounty.md](docs/external-miner/bounty.md) | Bounty miners | +| [docs/external-miner/proof.md](docs/external-miner/proof.md) | Proof miners | +| [docs/external-miner/validators.md](docs/external-miner/validators.md) | Validators | +| [docs/BOUNTY.md](docs/BOUNTY.md) / [docs/PROOF.md](docs/PROOF.md) | Operator challenge specs | +| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Process topology | +| [docs/COMPLETENESS.md](docs/COMPLETENESS.md) | What is actually wired | +| [docs/THREAT_MODEL.md](docs/THREAT_MODEL.md) | What is claimed, and what is not | +| [docs/runbooks/](docs/runbooks/) | Local e2e, staging, rotation, failover | +| [deploy/README.md](deploy/README.md) | Compose / droplets | +| [whitepaper.pdf](whitepaper.pdf) | Whitepaper | +| [SUPPORT.md](SUPPORT.md) | How to get help | -Working branch is **`main`**. Production ships from annotated tags `v*.*.*` cut on `main`. +## Contributing -## Develop (this repo) +Read [CONTRIBUTING.md](CONTRIBUTING.md) and [AGENTS.md](AGENTS.md) before you open a PR. Rust **1.96.0** via [`rust-toolchain.toml`](rust-toolchain.toml). `unsafe_code` is forbidden; `unwrap` / `expect` stay in tests. @@ -136,36 +131,19 @@ cargo run -p xtask -- design-check cargo run -p xtask -- external-docs-check ``` -Local full-subnet smoke (Docker Compose, testnet 541, optional tunnel): +Local smoke (Docker Compose, testnet 541): ```bash ./deploy/scripts/materialize-env.sh ./deploy/scripts/local-e2e.sh --smoke ``` -Details: [docs/runbooks/local-testnet-e2e.md](docs/runbooks/local-testnet-e2e.md) and [deploy/README.md](deploy/README.md). Do not commit `deploy/env/*.env`, wallets, or age identities. - -## Contributing - -Read [CONTRIBUTING.md](CONTRIBUTING.md) and [AGENTS.md](AGENTS.md) before you open a PR. - - Target **`main`**. Subject: `type(scope): summary` (lowercase, ≤72 chars). -- Frozen specs (`docs/BUNDLE_SPEC.md`, `docs/DESIGN_CHALLENGE.md`) are pinned by xtask. Do not rewrite incentive or consensus semantics in a drive-by. -- Do not rename `BASE_*` env vars, `/opt/base` paths, or `base-*-v1` domain tags. Those strings are measured into live droplets and miner CVMs. +- Frozen specs are pinned by xtask. Do not rewrite incentive or consensus semantics in a drive-by. +- Do not rename `BASE_*` env vars, `/opt/base` paths, or `base-*-v1` domain tags. - PRs need a [Greptile](https://greptile.com) review (`.greptile/`). If the bot is silent, comment `@greptileai review`. -- Security reports go through [SECURITY.md](SECURITY.md), not a public issue. - -## Documentation +- Security: [SECURITY.md](SECURITY.md). -| Doc | Audience | -|-----|----------| -| [docs/external-miner/README.md](docs/external-miner/README.md) | Miners (A→Z) | -| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Process topology | -| [docs/COMPLETENESS.md](docs/COMPLETENESS.md) | What is actually wired | -| [docs/THREAT_MODEL.md](docs/THREAT_MODEL.md) | What is claimed, and what is not | -| [docs/OPERATOR_SECURITY.md](docs/OPERATOR_SECURITY.md) | Operator checklist | -| [docs/runbooks/](docs/runbooks/) | Staging, local e2e, rotation, failover | -| [whitepaper.pdf](whitepaper.pdf) | Whitepaper | -| [SUPPORT.md](SUPPORT.md) | How to get help | +## License Apache License 2.0 — see [LICENSE](LICENSE).