From 8a265d82c79151d51c6eecbbc4d532efc90bd8d8 Mon Sep 17 00:00:00 2001 From: FlorianJeandenans Date: Thu, 6 Aug 2026 13:41:18 +0200 Subject: [PATCH 1/3] docs(adr): define decentralization roadmap and trust boundaries Add ADR-012, the accepted architecture record that issue #32 asks for: role vocabulary, per-role trust and threat model, a per-class data classification with a target placement column, cross-cutting guarantees (finality, conflict resolution, replay, data availability, erasure, key recovery), a five-stage migration mapped onto the v3.0-v6.0 milestones, and the table of follow-up ADR gates each stage still requires. ADR-012 authorizes no implementation by itself. Its purpose is to make milestones v3.0 through v6.0 plannable: every issue there was silently blocked by AGENTS.md's absolute prohibition list with no ADR to point at. AGENTS.md now separates prohibitions that no ADR lifts (hard-coded secrets, contract changes without consumer analysis, detailed metrics or tenant data on-chain) from those gated on a named follow-up ADR. No rule is weakened; the security, contract, and runtime rules are unchanged. ROADMAP.md is extended from v1.0 to v6.0 so it matches the GitHub milestones, and states that it and the milestones are the source of truth over architecture.md and architecture_review.md. Refs #32 Co-Authored-By: Claude Opus 5 --- AGENTS.md | 10 +- ROADMAP.md | 62 ++++ ...ralization-roadmap-and-trust-boundaries.md | 282 ++++++++++++++++++ 3 files changed, 353 insertions(+), 1 deletion(-) create mode 100644 docs/adr/012-decentralization-roadmap-and-trust-boundaries.md diff --git a/AGENTS.md b/AGENTS.md index ca4ab1f..a2588e9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,6 +14,10 @@ OpenInfra Network is a decentralized provider-cloud prototype. The MVP must join Do not change a language, framework, database, or component boundary without an accepted ADR. Components must not take over another component’s responsibilities. The Provider Agent never talks directly to the blockchain in the MVP. +## Staged Architecture + +The architecture above is frozen for the current stage, not forever. [ADR-012](docs/adr/012-decentralization-roadmap-and-trust-boundaries.md) defines the decentralization roadmap, the trust and threat model for every role, the per-class data classification, and the staged migration from today's single Control Plane to a decentralized network. Its §6 names the specific follow-up ADR that each later stage requires. A prohibition below is lifted only by accepting the ADR named there — never by an implementation deciding the change is small. + ## Integration and Contract Rules Generated Go and Rust types must derive from Protobuf; do not add manual copies. Before changing a `.proto`, identify every consumer, preserve wire compatibility, run breaking-change checks, regenerate both languages, and update tests and docs. PostgreSQL is authoritative off-chain; Redis contains only reconstructible state. Never report `RUNNING`, a successful deployment, or an on-chain transition before receiving authoritative confirmation. @@ -32,4 +36,8 @@ Use `make fmt`, `make lint`, `make test`, or component targets documented by `ma ## Prohibited Changes -Do not introduce Kubernetes, another database, direct Agent-to-chain access, runtime orchestration, detailed on-chain metrics, hard-coded secrets, or contract changes without consumer analysis. Every production feature requires tests and every architecture change requires an ADR. +Every production feature requires tests and every architecture change requires an ADR. + +**Permanent — no ADR lifts these.** Never hard-code secrets. Never change a contract without consumer analysis. Never put detailed metrics on-chain. Never put tenant payloads, logs, secrets, or any personal data on-chain: consensus state cannot be erased, so only hashes and commitments may cross that line (ADR-012 §3). + +**Prohibited until the ADR gate named in ADR-012 §6 is accepted.** Do not introduce another database (ADR-013, ADR-018), direct Agent-to-chain access (ADR-017), runtime orchestration (ADR-016), decentralized storage (ADR-018), a TEE trust root (ADR-019), or a replacement for `EnsureRoot` governance (ADR-020). Kubernetes remains prohibited under ADR-006, which fixes Docker as the runtime; adopting it needs its own accepted ADR. diff --git a/ROADMAP.md b/ROADMAP.md index 84be441..3716c1f 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,5 +1,14 @@ # Roadmap +This file and the GitHub milestones are the authoritative roadmap. `architecture.md` and +`architecture_review.md` §7 contain an older, conflicting version numbering and are aspirational +documents, not a record of what is planned or implemented. + +Milestones v3.0 and later are staged and gated by +[ADR-012](docs/adr/012-decentralization-roadmap-and-trust-boundaries.md), which defines the trust +boundaries, the data classification, and the follow-up ADR each stage requires. No implementation +in those milestones starts before its gate ADR is accepted. + ## v0.1 — Provider Join and First Workload Deliver the MVP in this dependency order: @@ -25,3 +34,56 @@ Complete authorized lease transitions, controlled reward arithmetic, event corre ## v1.0 — Stable Multi-Provider Network Harden multi-provider operation, upgrades, migrations, security, performance, reliability, compatibility, and operational documentation. Production readiness requires independent security review and measurable SLOs. + +## v1.1 — Metering and Settlement + +Add auditable usage metering, billing, escrow, settlement, and provider payouts after the stable MVP. Issues: #19 (metering and settlement architecture), #20 (usage metering and invoice ledger), #21 (on-chain escrow and provider settlement). #19 also gates streaming payments (#51) in v3.0. + +## v2.0 — OpenStack Compatibility + +Expose an OpenStack-compatible cloud surface backed by OpenInfra providers, including VM, identity, networking, storage, images, and Kubernetes integration. Issues: #22 (service mapping), #23 (Keystone identity), #24 (Nova/Placement), #25 (Neutron networking), #26 (Glance/Cinder), #27 (Kubernetes). + +This is an API-surface track, orthogonal to the decentralization stages below: it is neither blocked by them nor a prerequisite for them, provided it introduces no new central authority. Kubernetes (#27) needs its own ADR — ADR-006 currently fixes Docker as the runtime. + +## v3.0 — Decentralized Control Plane and Data + +Progressively remove centralized frontend, database, scheduler, and operational trust assumptions while preserving privacy, consistency, and recoverability. This is Stage 1 of ADR-012 §5: decentralize *authority*, while the data plane stays as it is. + +| Issue | Gate | +|---|---| +| #32 — decentralization roadmap and trust boundaries | ADR-012 (accepted) | +| #33 — replicated off-chain data plane | ADR-013 | +| #34 — multiple Control Planes and scheduling relays | ADR-014 | +| #35 — content-addressed frontend distribution | ADR-018 | +| #36 — decentralized identity, governance, validator operations | ADR-020 | +| #50 — orchestration in smart contracts | ADR-016 | +| #51 — streaming payments | #19 (v1.1), no new ADR | +| #52 — slashing for availability guarantees | ADR-015 | + +## v4.0 — P2P Mesh & Global Fabric + +Full P2P WireGuard mesh, DHT discovery, Virtual VPC and decentralized ingress/DNS. Stage 2 of ADR-012 §5: remove the Control Plane from the packet path. Depends on #36, because peer authentication cannot rest on a Control-Plane-issued allowlist once the Control Plane is no longer in the path. + +Issues #53 (P2P mesh), #54 (gateway nodes), #55 (decentralized DNS) — all gated by ADR-017. + +## v5.0 — Geo-Distributed Economy & Storage + +Geo-discovery, Proof of Resource (PoR), and decentralized S3/block storage. Stage 3 of ADR-012 §5: remove the Control Plane from discovery and make storage a first-class verified resource. + +| Issue | Gate | +|---|---| +| #56 — DHT geo-discovery | ADR-017 | +| #57 — Proof of Resource | none; extends ADR-007 and ADR-011 §3 | +| #58 — S3-compatible object storage | ADR-018 | +| #59 — replicated block volumes | ADR-018 | + +## v6.0 — Confidential Cloud & Auto-Healing + +TEE support, distributed attestation, auto-migration and P2P IaC. Stage 4 of ADR-012 §5: close the operator-collusion gap and remove human intervention from failure recovery. + +| Issue | Gate | +|---|---| +| #60 — TEE support (Intel SGX / AMD SEV) | ADR-019 | +| #61 — distributed enclave attestation | ADR-019 | +| #62 — auto-healing and workload migration | ADR-016 | +| #63 — infrastructure topology DSL | none while evaluated off-chain; ADR-016 if evaluated on-chain | diff --git a/docs/adr/012-decentralization-roadmap-and-trust-boundaries.md b/docs/adr/012-decentralization-roadmap-and-trust-boundaries.md new file mode 100644 index 0000000..78afb01 --- /dev/null +++ b/docs/adr/012-decentralization-roadmap-and-trust-boundaries.md @@ -0,0 +1,282 @@ +# ADR-012: Decentralization roadmap and trust boundaries + +## Status + +Accepted. + +## Context + +OpenInfra's stated goal is a decentralized provider cloud — general infrastructure +(CPU, RAM, storage, bandwidth) traded and verified the way Bittensor trades and +verifies machine-learning work, without the restriction to a single workload +class. The GitHub milestones now describe that path end to end (v0.1 through +v6.0), but the repository cannot legally execute on any of it. + +`AGENTS.md`'s "Prohibited Changes" section forbids "another database, direct +Agent-to-chain access, runtime orchestration" in absolute terms +(`AGENTS.md:35`), and its frozen-architecture rule forbids changing "a language, +framework, database, or component boundary without an accepted ADR" +(`AGENTS.md:15`). Those two rules are correct — they are what has kept the MVP +coherent — but between them they block every issue in milestones v3.0 through +v6.0: on-chain orchestration (#50), a WireGuard mesh with no central +configuration server (#53), DHT-based discovery (#56), a replicated off-chain +data plane (#33), and decentralized object and block storage (#58, #59). The +escape hatch is "every architecture change requires an ADR", and there is no ADR +to point at. Issue #32 asks for exactly this document and states that "no +architecture implementation starts before ADR acceptance." + +Decentralization is also not a single switch. Today every authoritative fact +about a provider passes through one operator: PostgreSQL is the sole off-chain +authority (ADR-005), a single Control Plane bridge account holds the root origin +for provider registration and lease management (`blockchain/runtime/src/lib.rs:160-161,208`), +and until ADR-011 the same account also produced every reputation number. +ADR-011 moved availability and reputation writes to signed, stake-bonded Network +Validators (`blockchain/runtime/src/lib.rs:219,241`) — the first genuine removal +of a central trust assumption, and the template for the rest. What is missing is +the map: which remaining facts move where, in what order, under which threat +model, and what may never move on-chain at all. + +This ADR is that map. It does **not** authorize any implementation by itself. + +## Decision + +### 1. Vocabulary + +Issue #32 and the architecture documents use overlapping names for different +things. These are the definitions this repository uses from here on. + +| Term | Definition | +|---|---| +| **Worker** / **Provider** | The same entity: an operator running a Provider Agent that advertises and delivers CPU/RAM/storage/network. ADR-011 says "Worker" when it means "the provider being scored". | +| **Network Validator** | A stake-bonded, independently operated product role that challenges Workers, evaluates delivered service, and submits attributable weights on-chain (ADR-011). Not a block producer. | +| **Chain Authority** | An Aura block producer / GRANDPA finality voter that keeps the chain live (ADR-009). Not a Network Validator. The two roles are deliberately separable and must never be conflated in code, docs, or metrics. | +| **Control Plane replica** | One independently operated instance of the Go Control Plane. Today there is exactly one and it is trusted; #34 makes replicas plural. | +| **Gateway node** | A node that terminates public ingress and routes into the private workload mesh (#54). Introduced at Stage 2; does not exist today. | +| **Storage node** | A node providing content-addressed object storage or replicated block volumes (#58, #59). Introduced at Stage 3; does not exist today. | +| **Tenant** / **User** | The party submitting a workload and owning its data and secrets. Has no on-chain identity today. | +| **Governance** | Whatever origin may change runtime parameters, suspend a validator, or authorize a runtime upgrade. Today this is `EnsureRoot` (`blockchain/runtime/src/lib.rs:316`), i.e. one sudo key. #36 replaces it. | + +### 2. Trust and threat model + +For each role: what it may assert, what the system trusts it for, what it must +never be trusted for, and how it fails when adversarial. + +| Role | May assert | Trusted for | Never trusted for | Adversarial modes | +|---|---|---|---|---| +| Worker | Its own inventory, its own challenge responses, container state | Nothing on its own — every claim it makes is either verified by a challenge or irrelevant | Its own reputation, its own availability, its own resource truth | Over-advertising capacity; forging challenge responses; going silent after payment; running the same hardware behind many identities (Sybil) | +| Network Validator | A signed score for a Worker it was assigned to, plus a hash of the underlying evidence | Producing one attributable weight per assigned round | Being the sole input to any score; scoring itself; scoring outside its committee | Collusion with a Worker; weight-copying from other validators; withholding submissions to degrade quorum; bribery | +| Chain Authority | Block production and finality votes | Liveness and ordering only | Any product-level judgement about a Worker | Censoring extrinsics; equivocation; halting finality | +| Control Plane replica | Off-chain orchestration state, workload lifecycle transitions | Stage 0: authoritative off-chain state. Stage 1+: one candidate view, reconciled against finalized chain facts | Being the sole authority for anything a tenant or provider depends on financially | Under/over-reporting its own providers; silently dropping commands; replaying or reordering state transitions; unilateral censorship of a tenant | +| Gateway node | Public routing for workloads that opted in | Reachability | Confidentiality or integrity of tenant traffic — traffic must be end-to-end protected through it | Traffic interception; selective blackholing; metadata harvesting | +| Storage node | Possession of a content-addressed blob or block replica | Serving bytes that match their advertised hash | Retention without a proof, or confidentiality without client-side encryption | Silent data loss; claiming storage it does not hold; correlating tenants by access pattern | +| Tenant | Its workload definition, its own signatures | Authorizing its own workloads and paying for them | Any claim about a provider's delivered service | Non-payment; abusive workloads; forged lease claims | +| Governance | Parameter changes, suspensions, runtime upgrades | Bounded, timelocked, auditable emergency action | Silent or instant changes to economics, origins, or upgrade paths | Capture by a single operator; rushed upgrade bypassing timelock; targeted suspension as censorship | + +Two threats cut across every role and are **not solved** by this ADR: + +- **Operator-level collusion.** Distinct `AccountId`s controlled by one human are + indistinguishable on-chain. ADR-011 §4 already flags this as an accepted gap, + mitigated only by bonded stake and quorum. Nothing below changes that; it needs + the slashing ADR (§6) and, ultimately, attestation (#60, #61). +- **Bootstrap centralization.** Every stage below has a period where too few + independent parties exist for its own quorum assumptions to hold. Each stage + must therefore state its degraded-quorum behavior and report it honestly rather + than reporting false success — the rule already in `AGENTS.md:19`. + +### 3. Data classification + +The central table. Placement classes are: **on-chain** (consensus state), +**content-addressed** (immutable, hash-named, replicated by any node), +**replicated** (mutable, multi-writer off-chain state), **encrypted** (at rest +and in transit, keyed by the data owner), **cached** (reconstructible, never +authoritative), **local-only** (never leaves the node). + +| Data class | Integrity need | Availability need | Privacy | Retention | Stage 0 placement (today) | Target placement | +|---|---|---|---|---|---|---| +| Node identity (public keys, accounts) | Consensus | Highest | Public | Permanent | On-chain (`pallet-provider-registry`, `pallet-network-validator`) | Unchanged | +| Private keys | Absolute | Node-local | Secret | Until rotated | Local-only (`agent-core::identity`) | Local-only — **never** replicated, never escrowed | +| Offers / advertised capacity | Consensus | High | Public | Current + bounded history | On-chain (`pallet-resource-market`) | Unchanged | +| Leases | Consensus | Highest | Public terms, private payload | Permanent | On-chain (`pallet-lease`) | Unchanged | +| Reputation vectors | Consensus | High | Public | Latest value only | On-chain aggregate (`pallet-reputation`), raw evidence off-chain by hash (ADR-011 §3) | Unchanged | +| Payments / Reward Points | Consensus | Highest | Public | Permanent | On-chain (`pallet-rewards`) | Unchanged + streaming settlement (#51) | +| Workload metadata (image ref, resource spec, env) | High | High | **Tenant-private** | Lease lifetime + audit window | PostgreSQL (`control-plane/migrations/000004_workloads.sql`) | Encrypted + replicated; only a commitment hash on-chain | +| Metrics | Attributable | Medium | Semi-private | Bounded window | PostgreSQL + Redis | Replicated + cached. **Never on-chain** — `AGENTS.md:35` bans detailed on-chain metrics and this ADR does not lift that | +| Logs | Attributable | Medium | **Tenant-private** | Bounded, tenant-configurable | Local + PostgreSQL | Encrypted, tenant-scoped, erasable | +| Secrets | Absolute | Tenant-controlled | **Secret** | Until rotated | Off-chain, injected at deploy | Encrypted with tenant-held keys. **Never on-chain, never content-addressed, never in a shared replica in plaintext** | +| Container images | Content hash | High | Public or tenant-private | Long | External registry | Content-addressed; the digest is pinned in the lease so the chain fixes *which* image ran without storing it | +| Dashboard / frontend assets | Reproducible build + signature | High | Public | Versioned, rollback-safe | Served by the Control Plane (`control-plane/internal/dashboard`) | Content-addressed (#35) | +| Audit evidence (challenge payloads, signed responses, timing traces) | Hash-anchored | Medium | Mixed | Long, bounded | Off-chain, referenced by `payload_hash` (ADR-011 §3) | Content-addressed, anchored by the same `payload_hash` | + +**Relationship to ADR-008.** ADR-008 remains accepted and remains the operative +rule for Stage 0; it draws the same line at a coarser grain ("provider identity, +offers, leases, validated availability, reputation, and Reward Points on-chain; +users, workload requests, orchestration history, metrics, logs, Docker state, and +secrets off-chain"). This ADR refines that boundary per data class and adds the +target column. Where the two are read together, ADR-008 governs what is +implemented today and this ADR governs what may be built next. Nothing here moves +a class from off-chain to on-chain. + +**The one-way rule.** On-chain data cannot be deleted. Therefore no personal +data, no tenant payload, no secret, and no log ever goes on-chain — only hashes +and commitments. This is a privacy constraint, not a storage-cost optimization, +and it is not waivable by a later ADR without a legal review. + +### 4. Cross-cutting guarantees + +- **Finality.** A fact is authoritative only when it is finalized on-chain, or + when it is off-chain state that has been reconciled against a finalized chain + fact. No component may report `RUNNING`, a successful deployment, a settled + payment, or a reputation change before that — the existing rule at + `AGENTS.md:19`, restated here because every stage below adds a new component + tempted to break it. +- **Conflict resolution.** Where multiple writers exist (Stage 1 onward), the + chain is the tiebreaker: off-chain replicas converge on the ordering implied by + finalized chain events, never on wall-clock time. Any state a replica holds that + cannot be tied to a finalized fact is, by definition, a cache. +- **Replay protection.** Generalize the pattern already proven in + `pallet-availability`: a monotonic per-subject sequence checked with + `sequence > LastProofSequence::::get(&provider)` + (`blockchain/pallets/availability/src/lib.rs:350,373`), plus a block-number + deadline (`Challenge { deadline }`, `blockchain/pallets/availability/src/lib.rs:102`, + rejected as `ChallengeTimeout` at `:308`). Every new signed message introduced + by a later stage must carry a subject, a sequence or nonce, and a deadline. No + new replay scheme is to be invented. +- **Data availability.** Content-addressed data is only as available as the nodes + pinning it. Any stage that moves a class to content-addressed storage must state + its pinning and retention strategy and must degrade to an explicit error, never + to a silent empty result. +- **Erasure and privacy.** Tenant-private classes (workload metadata, logs, + secrets, private images) must be erasable on request. This is why they are + encrypted with tenant-held keys rather than merely access-controlled: erasure of + the key is the erasure mechanism where the ciphertext may already be replicated. + Public on-chain classes are permanent by design and must contain no personal + data. +- **Key recovery and rotation.** Every role needs a rotation path that does not + lose accrued state: a Worker rotating keys must keep its reputation and leases; a + validator must keep its stake and its unbonding position; a tenant must keep + access to its encrypted data. Rotation is an on-chain link from old key to new + key, authorized by the old key, with the same bounded-window and replay rules as + above. Loss of a key without a prior rotation is not recoverable and must be + documented as such — no escrow, no backdoor. + +### 5. Staged migration + +Each stage removes one class of central trust. Stages are ordered by dependency, +not by ambition, and map onto the existing GitHub milestones so the roadmap and +the issue tracker cannot drift apart. + +**Stage 0 — today (v0.1 → v1.1).** One Control Plane, PostgreSQL authoritative, +Redis reconstructible, root-gated bridge for registration and leases, Docker +runtime, Control-Plane-configured WireGuard. ADR-008 and ADR-005 hold unchanged. +The only decentralized element is Network Validator scoring (ADR-011). Milestones +v0.2, v0.3, v1.0, v1.1 harden this; they do not decentralize it further. + +**Stage 1 — decentralize authority (v3.0).** Remove the single-operator +assumption from state, scheduling, identity, and economics, while the data plane +stays as it is: #33 replicated off-chain data plane, #34 multiple Control Planes +and scheduling relays, #35 content-addressed frontend, #36 decentralized identity +and governance, #50 on-chain orchestration, #51 streaming payments, #52 slashing. + +**Stage 2 — decentralize the data plane (v4.0).** Remove the Control Plane from +the packet path: #53 fully P2P WireGuard mesh, #54 gateway nodes for public +ingress, #55 decentralized DNS. Prerequisite: Stage 1's identity work (#36), +because peer authentication cannot rest on a Control-Plane-issued allowlist once +the Control Plane is no longer in the path. + +**Stage 3 — decentralize discovery and storage (v5.0).** Remove the Control Plane +from provider discovery and add storage as a first-class verified resource: #56 +DHT geo-discovery, #57 Proof of Resource, #58 S3-compatible object storage, #59 +replicated block volumes. + +**Stage 4 — verifiable and self-healing (v6.0).** Close the operator-collusion +gap left open by §2 and remove human intervention from failure recovery: #60 TEE +support, #61 distributed enclave attestation, #62 auto-healing and migration, #63 +infrastructure topology DSL. + +Milestone v2.0 (OpenStack compatibility, #22–#27) is an API-surface track. It is +orthogonal to this roadmap and is neither blocked by it nor a prerequisite for +it, provided it introduces no new central authority. + +### 6. ADR gates + +This ADR authorizes nothing. Each item below needs its own accepted ADR before +implementation, and that ADR is what lifts the specific `AGENTS.md` prohibition +named in the last column. + +| Gate | Unblocks | Prohibition it must lift, and what it must settle | +|---|---|---| +| **ADR-013** — replicated off-chain data plane | #33 | "another database". Must settle: event log vs CRDT, deterministic IDs, ordering, snapshots, pruning, and the PostgreSQL deprecation criteria | +| **ADR-014** — multi-Control-Plane and relay protocol | #34 | single-Control-Plane component boundary. Must settle: leader/leaderless rules, idempotency, peer admission, and how an Agent refuses an unauthenticated relay | +| **ADR-015** — slashing and economic penalties | #52 | none (new mechanism). Already demanded by ADR-011 §5, which ships rewards but explicitly defers slashing economics. Must settle: false-positive protection, appeals, and interaction with `dispute_round` | +| **ADR-016** — on-chain orchestration | #50, #62 | "runtime orchestration". Must settle: what scheduling logic is deterministic enough for the runtime, and what stays off-chain | +| **ADR-017** — P2P mesh and DHT discovery | #53, #54, #55, #56 | "direct Agent-to-chain access", and the Control-Plane-mediated key exchange in `control-plane/internal/wireguard/wireguard.go`. Must settle: peer authentication without a central introducer, and what stays lease-gated per ADR-010 | +| **ADR-018** — content-addressed distribution and decentralized storage | #35, #58, #59 | "another database". Must settle: pinning, retention proofs, erasure, and gateway trust | +| **ADR-019** — TEE and distributed attestation | #60, #61 | none (new trust root). Must settle: which vendor roots are trusted, revocation, and what an unattested provider may still do | +| **ADR-020** — decentralized identity, key rotation, and governance | #36 | `EnsureRoot` as governance (`blockchain/runtime/src/lib.rs:316`). Must settle: rotation and recovery per role, stake/delegation, timelocks, and emergency constraints | + +Three issues need **no new gate**: + +- **#57 Proof of Resource** extends the existing challenge model (ADR-007) and + evidence-summary model (ADR-011 §3) to CPU/RAM/GPU. It adds no trust boundary. + It does require a `protocol/proto` change with full consumer analysis per + `AGENTS.md:19`. +- **#51 streaming payments** is gated on the metering and settlement architecture + already scoped by #19 (milestone v1.1), not on a new ADR. +- **#63 IaC DSL** needs no gate while it is evaluated off-chain. If any part of it + is ever evaluated in the runtime, it falls under ADR-016 and inherits the + determinism, bounded-input, and no-floats rules of `AGENTS.md:23`. + +### 7. Trade-offs and rollback + +- **Performance.** Every stage trades latency for independence. On-chain + orchestration (#50) replaces a millisecond database write with a block time; + DHT discovery (#56) replaces an indexed query with a network walk. Each gate ADR + must state the latency budget it accepts and what stays off the critical path. +- **Cost.** Replication and content-addressed pinning multiply storage cost by + the replication factor, and on-chain writes cost fees permanently. Classes stay + off-chain by default; the burden of proof is on moving something on-chain. +- **Liveness.** Each stage adds a quorum whose bootstrap period has too few + independent participants. Degraded quorum must be surfaced explicitly — the + dashboard requirement in #29 is the template for every later stage. +- **Governance.** Stage 1 replaces one sudo key with a governance process. Until + #36 lands, every gate ADR above is adopted under the current single-key + authority, which is itself a centralization the roadmap is meant to remove. This + is accepted and time-bounded, not ignored. +- **Rollback.** Every stage must keep its predecessor operable for one release: + Stage 1 keeps PostgreSQL authoritative until #33's SLOs are met; Stage 2 keeps + Control-Plane-configured WireGuard as a fallback path; Stage 3 keeps the + registry query alongside the DHT; Stage 4's TEE requirement is opt-in per + workload, never network-wide. A stage that cannot be rolled back has not met its + exit criteria. + +### 8. Explicitly out of scope + +This ADR does not specify any mechanism. It does not choose a database, a DHT, a +storage network, a TEE vendor, a governance model, or a token economic policy — +those are the gate ADRs of §6. It does not solve operator-level collusion (§2). +It does not change any code, origin, or storage item today. + +## Consequences + +- Milestones v3.0 through v6.0 become plannable: every issue now names the ADR it + waits on instead of being silently blocked by `AGENTS.md`. +- `AGENTS.md`'s prohibition list is reframed from permanent to ADR-gated. The + rules themselves do not weaken — the security rules, the Protobuf contract + rules, and the runtime's no-floats/no-unchecked-arithmetic rules are untouched, + and each prohibition now names the specific gate that may lift it. The frozen + architecture stays frozen; it simply has documented doors. +- Eight further ADRs are now owed (§6). None of them may be skipped by declaring + an implementation "small", and each one is a separate change with its own + consumer analysis. +- The one-way rule in §3 permanently constrains the design: any future proposal to + put tenant data, logs, or secrets on-chain is out of order without a legal + review, regardless of how convenient it would be for verification. +- `architecture.md` and `architecture_review.md` §7 contain an older, conflicting + roadmap numbering (v0.1 PoC / v0.2 Prototype / v0.3 Beta / v1.0 Production). + `ROADMAP.md` and the GitHub milestones are the source of truth; those two + documents remain aspirational, as `CLAUDE.md` already warns. Reconciling them is + separate work. +- The `docs/adr/` directory contains two files numbered `009` + (`009-control-plane-provider-registration.md` and + `009-local-aura-grandpa-testnet.md`). This ADR takes `012` and does not renumber + them; the collision is noted so it is not repeated. From 4158ad743e94ccc114685b2f5fcde3ca04bcdbe0 Mon Sep 17 00:00:00 2001 From: FlorianJeandenans Date: Thu, 6 Aug 2026 13:49:46 +0200 Subject: [PATCH 2/3] docs: align the v0.3 heading with its GitHub milestone title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ROADMAP.md said "Leases and Rewards End-to-End" while the milestone is "v0.3 — Leases and Rewards E2E". Every other heading in the file now matches its milestone verbatim; this was the last one that did not. Co-Authored-By: Claude Opus 5 --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 3716c1f..947a9ac 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -27,7 +27,7 @@ The detailed entry conditions, exit criteria, and failure rules are documented i Add bounded Proof of Availability, heartbeat expiry, vector reputation updates, metrics summaries, failure handling, and integration tests across Agent, Control Plane, and chain. -## v0.3 — Leases and Rewards End-to-End +## v0.3 — Leases and Rewards E2E Complete authorized lease transitions, controlled reward arithmetic, event correlation, idempotent orchestration, recovery from partial failures, and multi-component observability. From 028890b80835db956ab543e558eaa452ecd6bf4b Mon Sep 17 00:00:00 2001 From: FlorianJeandenans Date: Thu, 6 Aug 2026 13:52:08 +0200 Subject: [PATCH 3/3] docs(adr): specify slashing and economic penalties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add ADR-015, the gate ADR-012 §6 names for #52 and the follow-up ADR-011 §5 explicitly demanded when it shipped validator rewards without any penalty. The investigation surfaced a prerequisite #52's description hides: providers bond nothing. pallet-network-validator takes a real bond (ReservableCurrency, MinStake, reserve on registration, release after UnbondingPeriod), but pallet-provider-registry has no Currency association and pallet-lease holds no collateral. There is nothing to slash today, so provider bonding is the larger half of #52 rather than a detail of it, and it lands in a pallet #52 does not mention. Key decisions: a slash may only cite finalized rounds that met quorum and survived their dispute window, and never a single round; being trimmed as an outlier is explicitly not evidence of dishonesty, since the trimmed mean discards honest edge cases identically; slashed funds are burned, never paid to the accuser or the counterparty, because either would manufacture an incentive to fabricate breaches; exiting stake stays slashable, with the UnbondingPeriod >= DisputeWindow + AppealWindow invariant asserted rather than left to parameter tuning. Slashing must not go live while EnsureRoot is the appeal authority, so #52 now also depends on #36. ROADMAP.md records that coupling. Refs #52 Co-Authored-By: Claude Opus 5 --- ROADMAP.md | 2 +- .../015-slashing-and-economic-penalties.md | 215 ++++++++++++++++++ 2 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 docs/adr/015-slashing-and-economic-penalties.md diff --git a/ROADMAP.md b/ROADMAP.md index 947a9ac..14a5d4f 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -58,7 +58,7 @@ Progressively remove centralized frontend, database, scheduler, and operational | #36 — decentralized identity, governance, validator operations | ADR-020 | | #50 — orchestration in smart contracts | ADR-016 | | #51 — streaming payments | #19 (v1.1), no new ADR | -| #52 — slashing for availability guarantees | ADR-015 | +| #52 — slashing for availability guarantees | ADR-015 (accepted); also depends on #36, and requires provider bonding first | ## v4.0 — P2P Mesh & Global Fabric diff --git a/docs/adr/015-slashing-and-economic-penalties.md b/docs/adr/015-slashing-and-economic-penalties.md new file mode 100644 index 0000000..4dcc73c --- /dev/null +++ b/docs/adr/015-slashing-and-economic-penalties.md @@ -0,0 +1,215 @@ +# ADR-015: Slashing and economic penalties + +## Status + +Accepted. + +## Context + +ADR-011 shipped Network Validator rewards and deliberately stopped short of +penalties: "slashing stake for provably bad submissions is the intended +long-term deterrent but its economic parameters need their own analysis — +**out of scope for this ADR**, tracked as follow-up work" (ADR-011 §5). ADR-012 +§6 records that follow-up as this ADR, and names it as the gate for issue #52. + +Today the network has exactly two penalties, and neither is economic: + +- **Earning nothing.** `close_round` credits `PointsPerAcceptedSubmission` only + to submitters that survive trimming + (`blockchain/pallets/network-validator/src/lib.rs:639`, accruing through + `pallet_rewards::accrue_points` at `blockchain/pallets/rewards/src/lib.rs:182`). + A validator that submits garbage loses its share of ten points per round and + nothing else. +- **Suspension.** `suspend` / `reinstate` + (`blockchain/pallets/network-validator/src/lib.rs:529,549`) flip a validator + out of the active set. They are gated on `SuspensionOrigin`, which the runtime + binds to `EnsureRoot` (`blockchain/runtime/src/lib.rs:316`) — one sudo key. + +Investigating #52 surfaced a prerequisite that its one-line description hides. +**Providers bond nothing.** `pallet-network-validator` takes a real bond — +`ReservableCurrency` (`lib.rs:161`), `MinStake` (`lib.rs:173`, bound to +`MinValidatorStake = 1_000` at `blockchain/runtime/src/lib.rs:106,317`), reserved +on registration (`lib.rs:449`) and released only after `UnbondingPeriod` +(`lib.rs:503`). `pallet-provider-registry` has no `Currency` association at all, +and `pallet-lease` holds no collateral. Issue #52 asks for "financial penalties +for providers that do not honor their availability commitments"; there is +currently nothing to take. Provider bonding is not an implementation detail of +#52 — it is a precondition, and it is the larger half of the work. + +Slashing is also the first mechanism in this repository that can destroy value +belonging to a participant on the strength of other participants' testimony. +That makes its failure mode qualitatively worse than anything shipped so far: a +wrong reputation number recovers on the next round, a wrong slash does not. + +## Decision + +### 1. Two subjects, one mechanism + +"Slashing" covers two different accusations that share machinery but not +evidence: + +| | Validator slashing | Provider slashing (#52) | +|---|---|---| +| Bonded today | Yes (`MinStake`) | **No — must be added, §2** | +| Accusation | Submitted evidence that is provably false or self-contradictory | Failed a committed availability level | +| Evidence | On-chain, from the validator's own signed submissions | Aggregated closed rounds, per ADR-011 §5 | +| Deferred by | ADR-011 §5 | Never specified | + +They are specified together because they must share the ordering rules of §5 and +the appeal path of §6; a network that can slash one party under weaker rules than +the other has simply moved the attack. + +### 2. Provider bonding (prerequisite for #52) + +Extend `pallet-provider-registry` with a bond, mirroring the shape already proven +in `pallet-network-validator` rather than inventing a second one: +`ReservableCurrency`, a reserve on registration, an `Exiting { available_at }` +status, and a `withdraw_unbonded` release path. + +- The bond is **required to hold leases**, not to appear in the registry. A + provider may register and be discoverable with no bond; it may not be scheduled + a workload. This keeps discovery permissionless while keeping obligations + collateralized. +- The bond scales with committed capacity, not a flat minimum. A flat bond makes + a large provider's downside negligible relative to its revenue while pricing a + small provider out — the parameter must be a function of what the provider has + promised, floored at a minimum. +- Reducing committed capacity below what an active lease requires is refused, not + silently accepted; a provider cannot shrink its bond out from under its + obligations. + +### 3. What is slashable evidence + +**Never a single party's word.** Concretely: + +- A slash may only cite a round that is `Final` — closed by `close_round` with at + least `MinQuorum` submissions — and whose `DisputeWindow` has fully elapsed with + no upheld dispute. +- A single bad round never slashes. Slashing triggers on a governed number of + **consecutive** qualifying rounds below a governed threshold. One round is + noise; a sustained pattern is a breach. +- Degraded quorum produces low confidence, never a penalty. A round that closed at + the quorum floor is weaker evidence than a full committee and must not be + counted toward a slash; this is the same honesty rule that #29 applies to the + dashboard. + +For validators specifically: + +- **Being trimmed as an outlier is not evidence of dishonesty.** The trimmed mean + in `close_round` discards the highest and lowest submission by construction, so + an honest validator observing a genuine edge case is trimmed exactly like a liar. + Persistent outlier status may inform selection or rewards; it must never, on its + own, slash. +- What is slashable: **equivocation** — two conflicting signed submissions for the + same `(provider, round, dimension)` — and evidence provably contradicted by the + `payload_hash` it committed to. Both are self-incriminating and need no + third-party judgement. + +### 4. Parameters + +These are the economic parameters ADR-011 §5 said needed their own analysis. All +are governed values, not constants compiled into a pallet. + +| Parameter | Meaning | Constraint | +|---|---|---| +| `SlashFractionBps` | Fraction of the bond destroyed per qualifying breach | Basis points, integer; small enough that one wrong slash is survivable, large enough to exceed the profit from the breach | +| `BreachRounds` | Consecutive qualifying rounds before a slash arms | Greater than one, by §3 | +| `SlashCooldown` | Minimum interval between slashes citing overlapping rounds | Prevents the same breach being slashed repeatedly | +| `AppealWindow` | Bounded window to contest an armed slash | §6; at least `DisputeWindow` | + +**Where slashed funds go.** Burned, or sent to a treasury — **never to the +accuser, and never to the counterparty of the slashed party.** Paying a slash out +to whoever reported it manufactures an incentive to fabricate breaches, and +paying it to the tenant makes every tenant a beneficiary of its provider's +failure. Compensation for a failed lease is a settlement question (#19, #21), not +a slashing question, and mixing them corrupts both. The MVP burns. + +**Accrued rewards are not clawed back.** `pallet-rewards` already documents this +for upheld disputes, and this ADR keeps it: points already credited stay +credited, and the penalty acts on the bond. Clawback across an unbounded history +is unbounded work in the runtime and is refused on those grounds. + +### 5. Ordering against disputes, exit, and finality + +- A slash **cannot be finalized while the round justifying it is `Disputed`**. + `dispute_round` and `resolve_dispute` + (`blockchain/pallets/network-validator/src/lib.rs:709,755`) already suspend and + resolve a round's reputation effect; a pending slash follows the same state. +- An upheld dispute **reverses** any slash armed on that round, releasing the + reserved amount. A rejected dispute lets it proceed. +- **Exit must not outrun a slash.** Stake in `Exiting { available_at }` remains + slashable until released by `withdraw_unbonded`. The invariant is + `UnbondingPeriod >= DisputeWindow + AppealWindow + BreachRounds × round length`; + today `ValidatorUnbondingPeriod = 14_400` against `ValidatorDisputeWindow = 300` + (`blockchain/runtime/src/lib.rs:107,115`), which leaves ample margin, but the + invariant must be asserted in the runtime rather than left to whoever next tunes + a parameter. +- Nothing is slashed on unfinalized state. A reorganization that removes the + qualifying round removes the slash with it. + +### 6. Appeals + +An armed slash is contestable within `AppealWindow` by the accused party, through +a bounded on-chain call, resolved by a governance origin. + +Today that origin would be `EnsureRoot` (`blockchain/runtime/src/lib.rs:316`) — +a single sudo key deciding whether to destroy a participant's stake. That is not +an acceptable terminal authority for an irreversible economic penalty, and it is +precisely the centralization the roadmap exists to remove. + +**Therefore: slashing does not go live before ADR-020** (decentralized identity +and governance, gating #36). The mechanism specified here may be implemented, +tested, and merged behind a disabled parameter; enabling it in a live network +requires the governance work first. ADR-012 §5 places #36 in the same stage as +#52, so this ordering costs no schedule. + +### 7. Arithmetic and safety + +Standard runtime rules from `AGENTS.md` apply and are restated because this +pallet destroys balances: no floats, checked or saturating arithmetic throughout, +a slash that can never exceed the reserved bond, never underflow it, and never +leave an inconsistent `Exiting` position. Every extrinsic carries an explicit +origin check. Weights are benchmarked, not stubbed — a slash path with a stub +weight is a denial-of-service vector. + +### 8. False positives + +The scenario this ADR most needs to survive is an honest provider that looks +unavailable because the observers are partitioned. + +- A partitioned committee cannot reach `MinQuorum`, the round does not qualify + under §3, and no slash arms. +- A colluding minority below quorum cannot close a round at all, which is the + property ADR-011 §4 already relies on. +- A colluding majority of a committee **can** slash an honest provider. This ADR + does not solve that; ADR-011 §4 flags operator-level collusion as an accepted + gap, and ADR-012 §2 repeats it. `BreachRounds` raises the cost — the colluders + must win the committee draw repeatedly — and the appeal path of §6 is the + backstop. Attestation (#61) is the real fix, and it is deliberately later. + +### 9. Out of scope + +Token economics and monetary policy; insurance or compensation markets for +slashed leases; reputation-weighted stake; and the concrete numeric values of §4, +which are governed parameters to be set at deployment, not architecture. + +## Consequences + +- **#52 is substantially larger than its description.** It cannot be implemented + as written, because providers hold no bond to slash. The bonding work of §2 + lands in `pallet-provider-registry` — a pallet #52 does not mention — and + changes the meaning of provider registration for every existing caller, + including the Control Plane's `register_provider_for` path (ADR-009). +- **#52 is now dependent on #36.** Section 6 forbids going live while `EnsureRoot` + is the appeal authority. This is a real schedule coupling and should be + reflected in issue ordering. +- The network gains its first irreversible operation. Every other mechanism to + date is corrigible on the next round; a finalized slash is not. This justifies + the conservative posture throughout: consecutive-round thresholds rather than + single-round triggers, burning rather than paying accusers, and no clawback. +- Being an outlier stays unpunished (§3). Honest validators reporting genuine + edge cases will keep being trimmed, and the network keeps paying that cost in + exchange for not punishing honest disagreement. +- A colluding committee majority can still slash an honest provider (§8). This + ADR bounds and prices that attack; it does not eliminate it, and no + implementation should claim otherwise.