Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ Every production feature requires tests and every architecture change requires a

**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.
**Prohibited until the ADR gate named in ADR-012 §6 is accepted.** Do not introduce another database (ADR-016, ADR-021), direct Agent-to-chain access (ADR-020), runtime orchestration (ADR-019), decentralized storage (ADR-021), a TEE trust root (ADR-022), or a replacement for `EnsureRoot` governance (ADR-023). Kubernetes remains prohibited under ADR-006, which fixes Docker as the runtime; adopting it needs its own accepted ADR.
28 changes: 14 additions & 14 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,38 +52,38 @@ Progressively remove centralized frontend, database, scheduler, and operational
| 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 |
| #33 — replicated off-chain data plane | ADR-016 |
| #34 — multiple Control Planes and scheduling relays | ADR-017 |
| #35 — content-addressed frontend distribution | ADR-021 |
| #36 — decentralized identity, governance, validator operations | ADR-023 |
| #50 — orchestration in smart contracts | ADR-019 |
| #51 — streaming payments | #19 (v1.1), no new ADR |
| #52 — slashing for availability guarantees | ADR-015 |
| #52 — slashing for availability guarantees | ADR-018 |

## 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.
Issues #53 (P2P mesh), #54 (gateway nodes), #55 (decentralized DNS) — all gated by ADR-020.

## 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 |
| #56 — DHT geo-discovery | ADR-020 |
| #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 |
| #58 — S3-compatible object storage | ADR-021 |
| #59 — replicated block volumes | ADR-021 |

## 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 |
| #60 — TEE support (Intel SGX / AMD SEV) | ADR-022 |
| #61 — distributed enclave attestation | ADR-022 |
| #62 — auto-healing and workload migration | ADR-019 |
| #63 — infrastructure topology DSL | none while evaluated off-chain; ADR-019 if evaluated on-chain |
35 changes: 26 additions & 9 deletions docs/adr/012-decentralization-roadmap-and-trust-boundaries.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,14 +205,14 @@ 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 |
| **ADR-016** — 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-017** — 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-018** — 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-019** — on-chain orchestration | #50, #62 | "runtime orchestration". Must settle: what scheduling logic is deterministic enough for the runtime, and what stays off-chain |
| **ADR-020** — 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-021** — content-addressed distribution and decentralized storage | #35, #58, #59 | "another database". Must settle: pinning, retention proofs, erasure, and gateway trust |
| **ADR-022** — 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-023** — 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**:

Expand All @@ -223,7 +223,7 @@ Three issues need **no new gate**:
- **#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
is ever evaluated in the runtime, it falls under ADR-019 and inherits the
determinism, bounded-input, and no-floats rules of `AGENTS.md:23`.

### 7. Trade-offs and rollback
Expand Down Expand Up @@ -280,3 +280,20 @@ It does not change any code, origin, or storage item today.
(`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.
- **§6's gate numbers were renumbered once, after the fact.** This ADR originally
reserved `ADR-013` through `ADR-020` for the eight gates above. `ADR-013` and
`ADR-014` were then accepted for unrelated, unplanned work (the Network
Validator daemon and wallet-based dashboard login, respectively — neither is a
Stage 1+ decentralization gate), and `ADR-015` was about to be claimed the same
way (independent bandwidth measurement) before this correction. Rather than let
`AGENTS.md`'s prohibition list keep citing gate numbers that actually name
something else, every gate in §6 (and every citation of it in `AGENTS.md` and
`ROADMAP.md`) was shifted by three: `ADR-013`→`ADR-016`,
`ADR-014`→`ADR-017`, `ADR-015`→`ADR-018`, `ADR-016`→`ADR-019`,
`ADR-017`→`ADR-020`, `ADR-018`→`ADR-021`, `ADR-019`→`ADR-022`,
`ADR-020`→`ADR-023`. `ADR-015` (bandwidth measurement) still lands as the real,
accepted `ADR-015` — a coincidence of timing with this correction, not a
renumbering of it. Future ADR numbers are assigned strictly in submission order
from whatever is next free at the time; this table is a *reservation of
intent*, not a claim on the number, and the next accepted ADR of any kind
(gate or not) takes the next integer regardless of what this table says.
117 changes: 117 additions & 0 deletions docs/control-plane/dashboard-decentralized-hosting-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Dashboard: migration path to decentralized static hosting

## Status

Planning note, not an ADR. It authorizes no implementation by itself — see "Relationship to
ADR-012" below. Written to close the corresponding item in issue #76 ("a migration path from the
MVP same-origin UI to decentralized static hosting — not written up anywhere yet").

## Where the dashboard is today (Stage 0)

`control-plane/internal/dashboard` serves the dashboard as static assets embedded directly in the
Control Plane's own Go binary (`//go:embed assets/*`, `internal/dashboard/dashboard.go`) at
`GET /dashboard/`, same-origin with every JSON API it calls (`/api/v1/overview`,
`/api/v1/validator-scores/{provider_id}`, the `/api/v1/auth/*` wallet-login endpoints). This is
exactly ADR-012 §3's Stage 0 placement for the "Dashboard / frontend assets" data class: "Served by
the Control Plane". It is also a single point of failure and a single point of trust — one
operator's binary is both the only place the UI can be fetched from and the only origin the
browser's `Content-Security-Policy` (`default-src 'self'`, `internal/dashboard/dashboard.go`'s
`securityHeaders`) will trust.

ADR-012 §3 already names the target: **content-addressed**, gated behind the still-unwritten
"content-addressed distribution and decentralized storage" ADR (renumbered `ADR-021` per ADR-012's
own "Consequences" correction — see that ADR for why the number moved). That gate ADR is scoped
far beyond the dashboard alone: it also covers S3-compatible object storage (#58) and replicated
block volumes (#59), and per ADR-012 §6 it "must settle: pinning, retention proofs, erasure, and
gateway trust" for *all three*. This document does not attempt to settle those — it only lays out
the dashboard-specific path so that work has somewhere to land once the gate ADR exists, and so
`#76`'s acceptance criterion has an honest answer today rather than silence.

## Why this is harder than "upload the build to IPFS"

The dashboard is not a static site today — it is a thin client over authenticated, live,
same-origin APIs:

- **Same-origin CSP.** `securityHeaders` sets `connect-src 'self'`. A dashboard served from a
content-addressed host (a different origin than the Control Plane API) needs a CSP that names the
API origin(s) explicitly, which reopens a CORS/CSRF design question this repository has not
needed to answer yet — today "same origin" *is* the authentication boundary for the unauthenticated
read endpoints (`agentEndpoint`, `validatorScores`), and loosening it changes that boundary.
- **Wallet login's origin binding.** ADR-014's challenge/signature flow (`internal/walletlogin`) and
its browser client (`assets/auth.js`) generate and store an Ed25519 keypair in the browser's
`localStorage`, which is origin-scoped by the browser itself. Moving the UI to a
content-addressed origin either fragments a user's stored key per hosting mirror (bad UX: "log
in again from every gateway") or requires a deliberate decision to widen key storage beyond
single-origin `localStorage` (a real security-relevant change, not a hosting detail).
- **Multiple Control Plane replicas don't exist yet.** ADR-012 Stage 1 (#34, gated by the
renumbered `ADR-017`) is what makes "which Control Plane API does this dashboard build talk to"
a real question with more than one honest answer. Decentralizing the frontend before
decentralizing the API it calls only decentralizes the part that was never the trust bottleneck.
- **Versioning and rollback.** A content-addressed build is immutable by construction (new build,
new hash). ADR-012 §7's rollback guarantee ("every stage must keep its predecessor operable for
one release") means an old, pinned build must keep working against a newer Control Plane API for
at least one release window — this repository's dashboard/API pairing has never had to be
backward compatible before, because there has only ever been one build talking to one API.

None of this is a reason not to do it. It is the reason it needs the gate ADR's actual
pinning/retention/erasure/gateway-trust decisions settled first, rather than a build script bolted
on ahead of them.

## Proposed staged path

Mirrors ADR-012 §5's own staging discipline: each stage removes one piece of the current
same-origin assumption, keeps the previous stage's path working, and is explicit about what
degrades if it fails.

**Stage 0 (today).** Embedded in the Control Plane binary, same-origin. No action needed; this
document changes nothing about it.

**Stage 0.5 — decoupled build, still Control-Plane-served (no new trust boundary).** Extract
`internal/dashboard/assets` into a standalone static build (its own `package.json`/build step is
optional — the assets are already hand-written HTML/CSS/vanilla JS with no bundler dependency
today, so "build" may just mean "lint and version-stamp"), still served by
`//go:embed` from the same binary at the same origin. This is pure refactoring with zero behavior
change and needs no ADR: it does not move any data class, per ADR-012 §3's "Nothing here moves a
class from off-chain to on-chain" framing (moving *how a build is produced* is not moving *where a
data class lives*). Value: makes every later stage a smaller diff, and lets CI verify the dashboard
build in isolation from the Go binary.

**Stage 1 — content-addressed mirror, Control-Plane-served remains the default and the source of
truth.** Publish each build's static output to content-addressed storage (IPFS or equivalent — the
gate ADR chooses) *in addition to* the existing `//go:embed` path, with the Control Plane
continuing to serve `/dashboard/` itself as the default entry point. The published hash is
advertised (e.g. a `GET /api/v1/dashboard-build` endpoint reporting the current build's hash),
letting an operator who wants to self-host or mirror it not depend on this Control Plane's uptime,
without yet requiring any browser trust the mirror over the origin. This needs the gate ADR's
pinning/retention answer (who keeps the content available, and for how long) but not its full
gateway-trust or multi-origin-CSP answer, since nothing about how the *default* dashboard is served
changes yet.

**Stage 2 — content-addressed as an explicit alternative, CSP widened deliberately.** Once ADR-012
Stage 1 (#34, multi-Control-Plane) has landed, widen `connect-src` to a configured allowlist of
known Control Plane API origins and document a supported way to run the dashboard build from a
content-addressed gateway against any of them. This is the point where the wallet-login
origin-scoping question above must be answered (widen key storage deliberately, or accept
per-origin re-login) — that decision belongs in the gate ADR, not here.

**Stage 3 — content-addressed as the default, Control-Plane-served becomes the fallback.** Flip the
default entry point once Stage 2 has run in production long enough to trust its gateway/pinning
story, keeping direct Control-Plane serving available per ADR-012 §7's rollback rule.

## What this document does not do

- It does not choose a content-addressing technology, a pinning provider, or a CDN — those are the
gate ADR's decisions (ADR-012 §6).
- It does not authorize starting Stage 0.5 or later — Stage 0.5 needs no ADR per the reasoning
above, but Stage 1 onward is gated the same way every other item in ADR-012 §6 is: "No
implementation in those milestones starts before its gate ADR is accepted" (`ROADMAP.md`).
- It does not resolve the wallet-login origin-scoping question raised in Stage 2 — flagged for the
gate ADR to settle, not decided here.

## Relationship to ADR-012

This document elaborates ADR-012 §3's "Dashboard / frontend assets" row and §6's `ADR-021` gate
(originally reserved as `ADR-018` before the renumbering documented in ADR-012's own
"Consequences" section) without being that gate ADR itself. When `ADR-021` is written, it should
supersede this document's staging proposal or explicitly adopt it — this file is not meant to be
maintained in parallel with an eventually-accepted ADR covering the same ground.