summaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/FOG-ALPHA.md184
-rw-r--r--docs/FOG-ARCHITECTURE.md1122
-rw-r--r--docs/FOG-COMPOSER.md1677
-rw-r--r--docs/FOG-CRYPTO-BENCHMARKS.md182
-rw-r--r--docs/FOG-CRYPTO-SUITES.md833
-rw-r--r--docs/FOG-LOCAL-POC.md345
-rw-r--r--docs/FOG-MESSAGING.md1013
-rw-r--r--docs/FOG-OBSERVABILITY.md718
-rw-r--r--docs/FOG-PKI.md1814
-rw-r--r--docs/FOG-POC-PRESERVATION.md152
-rw-r--r--docs/FOG-SECURITY-TEST-PLAN.md120
-rw-r--r--docs/FOG-SIMULATION.md321
-rw-r--r--docs/FOG-SPHINX-PROFILES.md1188
-rw-r--r--docs/FOG-STORAGE.md1507
-rw-r--r--docs/FOG-SX.md1032
-rw-r--r--docs/FOG-THREAT-MODEL.md962
-rw-r--r--docs/FOG-WIRE.md1246
17 files changed, 14416 insertions, 0 deletions
diff --git a/docs/FOG-ALPHA.md b/docs/FOG-ALPHA.md
new file mode 100644
index 0000000..03a712d
--- /dev/null
+++ b/docs/FOG-ALPHA.md
@@ -0,0 +1,184 @@
+# FOG Operator Alpha
+
+Status: Readiness gate, not deployable
+
+Date: 2026-08-18
+
+## 1. Purpose
+
+`FOG-OPERATOR-ALPHA-1` defines the transition from a single-host functional
+fixture to an experimental network operated across independent administrative
+domains. It consolidates the alpha requirements already present in
+`FOG-THREAT-MODEL`, `FOG-ARCHITECTURE`, `FOG-PKI`, and `FOG-WIRE` without
+activating a cryptographic, traffic, or deployment profile.
+
+The current FOG tree is not alpha-ready. No FOG protocol daemon or active
+byte-exact protocol profile exists. The alpha readiness module records this
+state explicitly and fails closed when evidence or operator separation is
+missing.
+
+## 2. Local Alpha Laboratory
+
+A single host may reproduce the alpha role count with separate rootless
+containers or virtual machines. That laboratory can test:
+
+- three-authority quorum and consensus failure;
+- two mix instances in each of three layers;
+- route selection across alternate nodes;
+- replay-state loss, node loss, storage loss, and partitions;
+- key rotation, revocation, epoch transition, and rollback behavior;
+- bounded queues, malformed input, flooding, and restart behavior;
+- deterministic deployment generation and role-specific containment.
+
+The laboratory must keep one executable, service account, secret scope,
+writable state scope, and network policy per role. A single container running
+all roles is not conforming because it erases the process, key, state, and
+network boundaries the test is intended to exercise.
+
+All laboratory binaries are compiled once for the host platform. One
+digest-pinned multi-binary fixture image may then be reused by every container,
+with a different single-role entrypoint. Six mix containers do not cause six
+`fog-mix` compilations.
+
+The laboratory does not demonstrate independent operation, provider or ASN
+diversity, Internet timing, resistance to operator collusion, or anonymity.
+Synthetic operator labels are test inputs only and must not be presented as
+real independence.
+
+## 3. Minimum Distributed Topology
+
+The operator alpha requires:
+
+- three independently administered authority roots and online services with
+ a 2-of-3 quorum;
+- independent consensus mirrors;
+- at least two independent checkpoint monitors or witnesses;
+- three mix layers with at least two independently operated mixes per layer;
+- at least four independently operated storage replicas;
+- separate entry, mix, courier, and storage identities;
+- declared operator family, administration, provider, provider-account, ASN,
+ country, and location relationships;
+- no route that repeats an operator or declared family.
+
+These are minimums, not evidence of sufficient anonymity. Traffic volume,
+cover scheduling, topology diversity, observed network behavior, and
+adversarial results remain part of every claim.
+
+Distributed operators consume verified release artifacts. The release
+pipeline assembles minimal role-specific images from one compiled artifact set
+and shared OCI layers. Operators do not need to compile locally unless they are
+performing an independent reproducibility check.
+
+## 4. Readiness Evidence
+
+Every required readiness item has one of two states: `open` or `pass`. A pass
+requires at least one immutable artifact reference, a lowercase SHA-256 digest,
+an explicit scope, and a date. A note or successful command without retained
+evidence does not close a gate.
+
+The required evidence covers:
+
+1. active byte-exact protocol profiles;
+2. real single-role protocol daemons;
+3. a validated operator inventory;
+4. unit, integration, conformance, fuzz, race, and fault testing;
+5. replay, tagging, n-1, flooding, load, side-channel, clock, consensus,
+ authority, node-loss, and storage-loss tests;
+6. traffic simulation calibrated with observed or conservative distributions;
+7. interoperability between independently built endpoints;
+8. reproducible independent-host deployment and rollback;
+9. rehearsed compromise, revocation, transition, quorum-loss, and restore
+ procedures;
+10. public admission, family, common-control, revocation, and residual-risk
+ policy;
+11. independent security review.
+
+The independent review gate is retained even though a broader production
+review is also required. For alpha it means that someone outside the
+implementation path has reviewed the exact experimental artifacts and that
+unresolved findings are recorded. It is not a production certification.
+
+## 5. Inventory Boundary
+
+The machine-readable operator inventory contains only bounded public or opaque
+identifiers needed to test separation and role counts. It must not contain:
+
+- private keys, recovery material, credentials, tokens, or passwords;
+- host login instructions or management addresses;
+- personal email addresses, phone numbers, or legal identity evidence;
+- private admission evidence or incident details;
+- packet, user, contact, mailbox, or capability identifiers.
+
+The validator rejects unknown fields, duplicate JSON keys, trailing values,
+oversized files, invalid identifiers, duplicate node identities, shared role
+state or secret scopes, insufficient role counts, and common administration,
+provider accounts, or families inside independence-critical role sets.
+
+The validator reports aggregate provider, ASN, country, and location-group
+counts. It does not invent a numeric diversity policy that the normative PKI
+profile has not selected.
+
+## 6. Claim Boundary
+
+The only permitted baseline label is:
+
+```text
+experimental-alpha-no-anonymity-claim
+```
+
+Until every gate passes, public material must say that FOG is a specification
+and laboratory project. Even after the alpha gate passes, results must identify
+the exact software, profiles, topology, traffic conditions, adversary,
+measurement period, known failures, and operator assumptions.
+
+An alpha must not claim production anonymity, global-passive-observer
+resistance, post-quantum security, reliable delivery, or protection against
+collusion merely because the minimum node count exists.
+
+## 7. Implementation
+
+The gate implementation lives in `deploy/alpha/`. It is deliberately separate
+from protocol daemons and uses only the Go standard library. It validates
+readiness evidence and an externally supplied operator inventory. It does not
+generate a deployment manifest because exact ports, transport profiles,
+cryptographic suites, cover schedules, operational limits, and authority time
+parameters remain non-active selections.
+
+## 8. Requirement Traceability
+
+| Alpha control | Requirements |
+| --- | --- |
+| Independent authority, mix, storage, mirror, and witness sets | `TM-PKI-01`, `TM-PKI-03`, `ARC-001`, `ARC-007`, `PKI-INV-01`, `PKI-INV-07` |
+| Six mixes, two per layer | `TM-ROLE-02`, `ARC-003`, `FOG-ARCHITECTURE` section 16.2 |
+| Evidence registry | `TM-SUPPLY-01`, `TM-CRYPTO-02`, `FOG-THREAT-MODEL` section 16.2 |
+| Unique service, state, and secret scopes | `TM-CRYPTO-01`, `ARC-007`, `WIRE-INV-07` |
+| Strict bounded inventory parser | `TM-AVAIL-01`, `ARC-008` |
+| No anonymity claim | `TM-NET-01`, `TM-NET-02`, `TM-NET-03`, `ARC-009` |
+
+## 9. Next Implementation Block
+
+The next safe local block is a simulation-only alpha laboratory with three
+authority fixtures, two mixes per layer, four storage fixtures, alternate-path
+traversal, and an expanded fault matrix. It must reuse no production profile
+identifier and must remain visibly distinct from the later protocol daemons.
+
+The completed laboratory is preserved as `FOG-ALPHA-LAB-POC-1` according to
+`FOG-POC-PRESERVATION.md`. Preservation includes reproducible source and one
+bounded demonstration workflow, not captured mutable containers or runtime
+secrets. The frozen PoC remains functional evidence only.
+
+The checked-in definition gate fixes 17 roles, 23 pairwise permitted edges,
+all eight complete mix routes, and 13 fault families in
+`deploy/alpha/lab-topology.json` and `deploy/alpha/lab-faults.json`. Compatible
+single-role fixtures and deterministic Compose generation now make the strict
+validator report `runnable: true`. The bounded one-command rootless workflow
+completed all eight routes, performed 102 containment and exact-network
+checks and exercised all 13 fault families, including exact stale-state
+rejection and fixture cover-scheduler supervision. It recorded sanitized
+evidence and removed every disposable runtime resource. Dependency and license
+inventory, frozen artifact hashes, and independent clean-room reproduction
+remain required before accepting the preserved PoC. The canonical preservation
+manifest now records zero third-party Go modules, exact external tool versions
+and licenses, required source and evidence hashes, and all eight binary hashes.
+The project license remains `NOASSERTION`; an independent host rebuild and
+repository revision remain outstanding.
diff --git a/docs/FOG-ARCHITECTURE.md b/docs/FOG-ARCHITECTURE.md
new file mode 100644
index 0000000..9060c7c
--- /dev/null
+++ b/docs/FOG-ARCHITECTURE.md
@@ -0,0 +1,1122 @@
+# FOG Architecture
+
+Status: Draft 0.1
+
+Date: 2026-08-08
+
+## 1. Purpose
+
+This document defines the normative component architecture, trust boundaries,
+information flows, state ownership, deployment units, and dependency rules for
+the FOG autonomous mix network.
+
+It refines `FOG-THREAT-MODEL.md`. It does not select final cryptographic
+algorithms, packet geometry, delay distributions, or active numeric message,
+storage, and Composer suites. Those decisions belong to narrower protocol
+specifications and MUST satisfy the boundaries defined here.
+
+FOG is not implemented yet. Statements in this document are design
+requirements, not claims about deployed software.
+
+The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, and MAY describe
+normative requirements in the sense of BCP 14 when they appear in uppercase.
+
+## 2. Architectural Scenario
+
+FOG is one product and one coordinated protocol suite with multiple
+independently deployable security roles. It is not a single daemon, a shared
+database application, or a collection of unrelated public microservices.
+
+The baseline implementation shape is:
+
+- one source repository and release process;
+- one separately built executable for each online security role;
+- a networkless Composer executable and image profile;
+- small protocol libraries with strict dependency direction;
+- a public client SDK with a deliberately narrow surface;
+- a simulator and conformance corpus in the same repository;
+- local Podman deployment only for the functional PoC;
+- independent hosts and operators where a deployment makes anonymity claims.
+
+Separate processes are justified by independent deployment, key ownership,
+network policy, compromise containment, and operator ownership. Application
+features that do not need a server-side trust boundary MUST remain modules,
+not daemons.
+
+## 3. Core Architectural Invariants
+
+The following invariants apply to every profile.
+
+### ARC-001: No universal trust domain
+
+No process, host, operator account, database, management system, or private key
+MAY be required to observe or control the complete user-to-storage path.
+
+### ARC-002: The Composer is networkless
+
+`fog-compose` MUST have no network interface. All external input and output
+cross explicit bounded transfer interfaces. A network-capable convenience
+mode is not a conforming Composer profile.
+
+### ARC-003: No data-plane bypass
+
+Native user operations MUST traverse an entry, all configured mix layers, and
+a terminal courier or service endpoint. Failure handling MUST NOT introduce a
+direct client-to-courier, client-to-storage, entry-to-storage, or
+mix-to-clearnet path.
+
+### ARC-004: Three distinct cryptographic layers
+
+Message end-to-end protection, KEMSphinx routing protection, and adjacent-node
+Noise transport MUST use purpose-separated protocols and keys. Success or
+failure of one layer MUST NOT be interpreted as validation of another.
+
+### ARC-005: Complete authenticated network view
+
+Route construction, entry eligibility, node roles, packet profiles, security
+parameters, and key validity MUST derive from a complete threshold-authenticated
+consensus accepted by the Composer. A relay-supplied partial view MUST NOT
+control route construction.
+
+### ARC-006: Uniform external behavior
+
+Native applications MUST share consensus-authorized packet classes, routing
+rules, retry classes, and cover processing. Core nodes MUST NOT vary packet
+geometry or parser selection according to `fog-drop`, `fog-mailbox`, or
+`fog-im`.
+
+### ARC-007: One private-key owner
+
+Each private key MUST have one owning role and one purpose. Separate roles MUST
+NOT share private key files, secret volumes, writable state directories, or
+backup credentials.
+
+### ARC-008: Bounded state and parsing
+
+Every queue, cache, request, response, parser, retry sequence, and storage
+operation MUST have explicit size, time, and resource bounds. Unknown-critical,
+non-canonical, expired, or unauthenticated input MUST fail closed.
+
+### ARC-009: Privacy-aware failure
+
+Availability recovery MUST preserve the declared layer count, packet class,
+authenticated profile, entry constraints, cover policy, and consensus
+freshness. If it cannot, the affected operation MUST stop and report a local
+coarse failure.
+
+### ARC-010: No inherited external guarantee
+
+Tor, Nym, Katzenpost, YAMN, SMTP, NNTP, and foreign Sphinx networks are not
+runtime dependencies of the FOG core. An edge bridge terminates the FOG trust
+claim and MUST publish a separate threat model.
+
+## 4. System Planes
+
+FOG separates four planes:
+
+1. **Offline user plane**: plaintext, identities, contacts, message state,
+ storage capabilities, route construction, and validation inside the
+ Composer.
+2. **Anonymous data plane**: entry, stratified mixes, courier, native service
+ endpoints, and storage replicas carrying fixed-class opaque traffic.
+3. **Consensus control plane**: node descriptors, authority voting,
+ threshold-signed consensus, revocation, profile authorization, and
+ equivocation evidence.
+4. **Operations and release plane**: local administration, signed builds,
+ configuration generation, coarse metrics, backups, incident response, and
+ updates.
+
+These planes MAY share public code and formats. They MUST NOT share universal
+credentials or writable runtime state.
+
+```text
+ consensus control plane
+ node descriptors -> authorities -> signed consensus
+ |
+ v
+offline user plane anonymous data plane
+
+Composer -> transfer -> blind relay -> entry -> L1 -> L2 -> L3 -> courier
+ ^ | |
+ | | v
+ +---- opaque input <-+ storage replicas
+
+ operations and release plane
+ signed artifacts, local administration, coarse aggregates
+```
+
+## 5. Data Classification
+
+Architecture and protocol documents MUST label fields and state using these
+classes or a stricter derived scheme.
+
+| Class | Meaning | Examples |
+| --- | --- | --- |
+| `PUBLIC-AUTH` | Public but authenticity or freshness matters | consensus, descriptors, release metadata, protocol profiles |
+| `OPAQUE-META` | Encrypted content with sensitive timing or relationship metadata | KEMSphinx packets, transfer bundles, reply envelopes, relay queues |
+| `CAPABILITY` | Possession grants a read, write, reply, or recovery operation | mailbox capabilities, reply blocks, rendezvous handles |
+| `SECRET-ROLE` | Private material owned by one online role | Noise, KEMSphinx, authority, replica, queue-sealing keys |
+| `SECRET-USER` | User secret or conversation state | identity keys, ratchet state, contact state, backup keys |
+| `PLAINTEXT-USER` | Decrypted user content | drafts, messages, rendered attachment content |
+| `AGGREGATE` | Delayed and privacy-reviewed operational data | thresholded loss or availability measurements |
+
+`CAPABILITY`, `SECRET-ROLE`, `SECRET-USER`, and `PLAINTEXT-USER` MUST NOT enter
+logs, metrics, command lines, crash reports, descriptors, consensus, or support
+bundles.
+
+## 6. Trust Domains and Deployment Units
+
+Each row is a distinct security domain even when the PoC places containers on
+one host.
+
+| Domain | Baseline deployable | Primary state owner | Network position |
+| --- | --- | --- | --- |
+| Offline user | `fog-compose` | user identity, contacts, message and capability state | no network |
+| Transfer receiver | restricted adapter owned by `fog-client-relay` | bounded incomplete transfer state | local physical input only |
+| Online user relay | `fog-client-relay` | opaque queues, schedules, temporary entry and return state | client edge |
+| Directory authority | `fog-authority` | descriptors, votes, consensus and revocation state | control plane only |
+| Entry | `fog-entry` | bounded ingress and temporary return state | edge of data plane |
+| Mix layer | `fog-mix` with fixed layer assignment | delay queues, replay state, epoch keys | one stratified layer |
+| Courier | `fog-courier` | bounded request deduplication and replica dispatch state | terminal mix service |
+| Storage | `fog-store` | opaque boxes, tombstones, replica metadata | behind courier |
+| Optional native service | `fog-service-*` | minimum service-specific opaque state | terminal mix service |
+| Observer | `fog-observer` | delayed coarse aggregates | operations plane |
+| Release | offline release tooling | release signing and provenance state | outside runtime network |
+| External bridge | `fog-bridge-*` | bridge-specific state | outside core guarantee |
+
+A conforming executable MUST activate exactly one online role. Multi-role
+configuration flags are forbidden outside explicitly labeled local simulation
+fixtures.
+
+## 7. Role Contracts
+
+### 7.1 `fog-compose`
+
+The Composer is the only core component authorized to handle user plaintext,
+user identity private keys, contact secrets, message state, and mailbox
+capabilities.
+
+It MUST:
+
+- verify release, consensus, contact, recovery, and message authenticity;
+- persist the highest accepted consensus epoch and rollback state;
+- build message-level ciphertext before export;
+- select internal routes from the authenticated consensus;
+- construct KEMSphinx packets, reply material, and storage operations;
+- create fixed-class opaque work items for the blind relay;
+- consume inbound bundles only after complete bounded parsing and
+ cryptographic verification;
+- store mutable secrets in an authenticated encrypted state store;
+- minimize plaintext lifetime and exclude plaintext from generic desktop
+ services, swap, previews, indexing, and crash dumps.
+
+It MUST NOT:
+
+- open a network socket or expose an HTTP, RPC, shell, or plugin server;
+- delegate message encryption, route selection, capability derivation, or
+ contact authentication to the blind relay;
+- import generic archives, office documents, HTML, scripts, executable files,
+ or unbounded media;
+- accept a lower consensus epoch without an explicit authenticated recovery
+ procedure.
+
+`fog-drop`, `fog-mailbox`, and `fog-im` are initially Composer-side application
+modules over shared messaging and storage protocol libraries. They are not
+independent network daemons in the initial architecture.
+
+Threats addressed: `TM-ENDPOINT-01`, `TM-ENDPOINT-02`, `TM-ENDPOINT-03`,
+`TM-APP-01`, `TM-CRYPTO-01`, `TM-PKI-02`.
+
+### 7.2 Transfer receiver
+
+The transfer receiver is a minimal adapter at the blind-relay boundary. It MAY
+decode QR or one explicitly configured FOG-SX physical backend. It MUST output
+only a bounded opaque FOG bundle to the relay queue.
+
+It MUST run without access to relay network credentials, queue decryption
+keys, user identity keys, or general filesystems. FEC and transport checksums
+MUST be completed before the inner bundle enters the relay, but they MUST NOT
+be treated as authenticity.
+
+The high-assurance offline-to-online path MUST have no automatic reverse data
+channel. Online-to-offline input uses a separately controlled visual or
+receive-only import path and is not the reverse channel of FOG-SX.
+
+Threats addressed: `TM-ENDPOINT-02`, `TM-AVAIL-01`.
+
+### 7.3 `fog-client-relay`
+
+The blind relay is the online scheduling and transport agent for one local
+Composer profile. It is allowed to know that its local user is using FOG and
+to observe local submission and import times. It MUST remain blind to
+plaintext, contacts, capabilities, application type, and the internal mix
+route.
+
+It MUST:
+
+- maintain bounded encrypted-at-rest queues of opaque work items;
+- fetch complete consensus documents and pass them unmodified to the Composer;
+- verify enough public consensus metadata to reject obvious network misuse,
+ while treating the Composer as the final consensus authority for user work;
+- choose an entry only from the Composer-authorized temporary candidate set;
+- follow consensus-authorized transmission, retrieval, cover, retry, and
+ failure classes;
+- generate client cover and loop traffic without using user identity or
+ contact secrets;
+- maintain only short-lived, opaque return rendezvous state;
+- transfer received opaque bundles to the controlled Composer import path;
+- erase expired work, return state, and incomplete transfers according to
+ explicit limits.
+
+It MUST NOT:
+
+- parse message or service payloads;
+- construct or rewrite the Composer's internal route;
+- hold message identity keys, mailbox capabilities, contact vouchers, ratchet
+ state, or release signing keys;
+- bypass an entry after failure;
+- expose a general-purpose proxy, SOCKS, VPN, TUN, SMTP, NNTP, or web API;
+- use a stable remote account identity as the default entry authentication
+ mechanism.
+
+The relay MAY select among opaque entry-specific submission variants prepared
+by the Composer. The exact entry-capsule and fallback construction is defined
+by `FOG-WIRE` and `FOG-SPHINX-PROFILES`; the relay MUST NOT learn the first
+internal mix hop from that construction.
+
+Threats addressed: `TM-NET-01`, `TM-NET-02`, `TM-NET-03`, `TM-NET-06`,
+`TM-ROLE-01`, `TM-ENDPOINT-01`, `TM-OPS-01`.
+
+### 7.4 `fog-authority`
+
+Authorities collectively define the authenticated network view. They do not
+carry user data-plane packets.
+
+Each authority MUST:
+
+- authenticate and validate descriptors for admitted role identities;
+- record declared operator families and deployment attributes;
+- validate role, layer, key, profile, address, epoch, and revocation rules;
+- exchange signed votes with peer authorities;
+- produce canonical consensus only at the configured threshold;
+- archive sufficient signed material to diagnose rollback and equivocation;
+- publish current and next public keys with bounded overlap;
+- separate long-term authority identity and recovery material from online
+ voting state;
+- fail deterministically when a quorum or time condition is not met.
+
+An authority MUST NOT:
+
+- inject data-plane traffic through privileged paths;
+- assign one process to multiple data-plane roles;
+- unilaterally create a valid consensus;
+- automatically trust a replacement authority or node identity;
+- receive user capabilities, packet identifiers, or fine-grained flow data.
+
+Consensus distribution MAY use multiple mirrors, but mirrors are untrusted
+transport. Signatures, epoch monotonicity, validity, and profile authorization
+are verified at every consumer.
+
+Threats addressed: `TM-PKI-01`, `TM-PKI-02`, `TM-PKI-03`, `TM-NET-06`,
+`TM-SUPPLY-01`.
+
+### 7.5 `fog-entry`
+
+The entry is an access gateway distinct from the three privacy-relevant mix
+layers. It accepts relay sessions, normalizes ingress handling, and dispatches
+opaque KEMSphinx packets to layer 1.
+
+It MUST:
+
+- authenticate itself through the fixed entry link profile;
+- authorize submission using short-lived, consensus-bound material rather
+ than a stable user account by default;
+- accept only fixed-class opaque submissions for the active epoch;
+- decrypt or validate only the entry capsule needed to learn the authorized
+ first internal hop and packet binding;
+- forward only to consensus-authorized layer-1 nodes;
+- maintain bounded queues and non-amplifying failure behavior;
+- process real and cover submissions through the same path;
+- support bounded, opaque, short-lived return rendezvous where required by the
+ reply protocol;
+- perform exactly one terminal KEMSphinx unwrap on an authorized reply route
+ when the return profile requires it, using a dedicated entry-return key and
+ never a mix-layer or entry-capsule key.
+
+It MUST NOT:
+
+- process an internal KEMSphinx mix layer or any forward KEMSphinx hop merely
+ because it is an entry;
+- perform a reply-terminal unwrap outside an authenticated return-rendezvous
+ context or forward the result as if it were another mix hop;
+- learn the complete route, final service, mailbox capability, contact, or
+ plaintext;
+- select or rewrite the internal route;
+- forward directly to layer 2, layer 3, courier, storage, bridge, or Internet;
+- retain a durable per-user mailbox or account in the core profile;
+- produce application-specific errors or timing classes.
+
+The exact entry capsule and return rendezvous are protocol decisions. They
+MUST preserve Composer route authority and relay blindness. An implementation
+convenience MUST NOT silently make the entry the first of only three total
+hops.
+
+Threats addressed: `TM-NET-01`, `TM-NET-03`, `TM-NET-06`, `TM-ROLE-01`,
+`TM-AVAIL-01`.
+
+### 7.6 `fog-mix`
+
+Every mix executable has one fixed layer assignment from the current
+consensus. It is a cryptographic router, not an application server.
+
+It MUST:
+
+- authenticate adjacent eligible nodes through the fixed node link profile;
+- accept packets only from roles permitted for its layer;
+- perform exactly one KEMSphinx hop transformation;
+- validate the packet profile, epoch, replay tag, routing command, and delay
+ bounds before enqueueing;
+- persist replay state for the required maximum packet lifetime;
+- delay and schedule packets according to the authenticated profile;
+- process real, loop, decoy, forwarded, and reply traffic uniformly within
+ their authorized packet class;
+- forward only to the next authorized layer or terminal role;
+- enforce bounded queues, connection counts, cryptographic work, and retries;
+- emit only coarse local health aggregates.
+
+It MUST NOT:
+
+- expose application plugins, storage APIs, user accounts, or general proxy
+ functions;
+- select an arbitrary next layer or skip a layer;
+- parse message, capability, courier, storage, or bridge payloads;
+- share KEMSphinx private keys or replay databases with another role;
+- log packets, replay tags, routes, per-packet delay, or fine-grained timing.
+
+Loss of valid replay state places the node outside the active privacy profile.
+It MUST stop packet processing until safe state is restored or a new epoch
+with fresh keys begins according to the replay specification.
+
+Threats addressed: `TM-NET-01`, `TM-NET-03`, `TM-NET-04`, `TM-NET-05`,
+`TM-NET-06`, `TM-ROLE-02`, `TM-OPS-01`, `TM-AVAIL-01`.
+
+### 7.7 `fog-courier`
+
+The courier is the terminal data-plane mediator between anonymous requests and
+storage or a separately declared native service. It terminates only the final
+KEMSphinx service envelope and MUST not learn the client network origin.
+
+It MUST:
+
+- accept terminal packets only after all configured mix layers;
+- parse one bounded, versioned courier command set;
+- dispatch opaque encrypted operations to eligible replicas;
+- keep replica selection knowledge separate from final capability-derived
+ record location where the storage construction requires it;
+- keep only bounded, expiring request-deduplication and reply state;
+- use single-use reply material or an equivalently reviewed construction;
+- return replies through a consensus-authorized anonymous reply route;
+- apply identical outer behavior to reads, writes, misses, retries, expected
+ outcomes, and cover operations as defined by `FOG-STORAGE`;
+- enforce non-amplifying limits before expensive or fan-out work.
+
+A courier acceptance reply is not replica durability or message delivery. The
+courier MUST preserve opaque final-replica receipt material without creating
+or interpreting it.
+
+It MUST NOT:
+
+- receive user identity keys, message plaintext, contact state, or long-term
+ mailbox capabilities;
+- connect directly to a blind relay or Composer;
+- expose replicas directly to clients or mixes;
+- become a durable mailbox database;
+- load arbitrary third-party plugins in the core process;
+- send data to the Internet or an external bridge under the core profile.
+
+Threats addressed: `TM-NET-01`, `TM-NET-02`, `TM-NET-05`, `TM-ROLE-03`,
+`TM-APP-01`, `TM-AVAIL-01`.
+
+### 7.8 `fog-store`
+
+Storage replicas hold authenticated encrypted records addressed through
+capability-derived, rotating, pseudorandom locations. They are not public
+mailbox servers.
+
+Each replica MUST:
+
+- authenticate couriers and eligible replica peers through a fixed node link
+ profile;
+- accept only bounded courier or replica protocol operations;
+- validate record authentication before committing state;
+- issue purpose-separated authenticated receipts only after durable local
+ commit under the exact active storage manifest;
+- implement idempotent writes, explicit expiry, tombstones, quotas, bounded
+ retention, and garbage collection;
+- keep replica and storage-envelope keys separate from node link keys;
+- return fixed-class authenticated encrypted results;
+- support the replica-independence and intermediate/final separation required
+ by the selected storage profile;
+- encrypt storage media and backups as defense in depth without treating disk
+ encryption as end-to-end protection.
+
+It MUST NOT:
+
+- accept connections from Composers, blind relays, entries, or ordinary mixes;
+- receive user plaintext or message identity private keys;
+- expose record existence through a public unauthenticated lookup interface;
+- share a writable database, database credentials, or backup key with another
+ replica operator;
+- publish per-record or fine-grained access metrics.
+
+The intended privacy profile requires at least four independently operated
+replicas. A smaller local fixture is functional testing only and MUST disable
+the corresponding unlinkability claim.
+
+Threats addressed: `TM-NET-02`, `TM-ROLE-03`, `TM-ENDPOINT-03`,
+`TM-CRYPTO-01`, `TM-AVAIL-01`.
+
+### 7.9 Native application modules and optional services
+
+The initial `fog-drop`, `fog-mailbox`, and `fog-im` state machines run inside
+the Composer and produce a common bounded message/storage envelope. Their
+network traffic MUST be indistinguishable within the declared packet class.
+
+A future feature MAY require a server-side `fog-service-*` executable. Such a
+service MUST:
+
+- be a separately keyed terminal role behind all mix layers;
+- declare its exact request fields and information exposure;
+- accept one fixed bounded protocol, not arbitrary code or generic HTTP;
+- use anonymous reply routes;
+- receive no privilege to call unrelated services or public Internet targets;
+- add a threat-model extension and independent conformance tests.
+
+No service is permitted to weaken the common packet profile or make the
+courier parse application plaintext.
+
+Threats addressed: `TM-NET-06`, `TM-APP-01`, `TM-ROLE-03`.
+
+### 7.10 `fog-observer`
+
+The observer receives delayed, coarse, thresholded aggregates. It is not a
+packet-flow collector.
+
+It MUST:
+
+- accept only a versioned aggregate schema;
+- enforce release delay, minimum population, and suppression rules;
+- separate operator health views from public views;
+- expire raw signed aggregate submissions after bounded processing;
+- publish the aggregation and differencing-risk policy.
+
+It MUST NOT:
+
+- receive packet IDs, replay tags, capabilities, user IDs, full routes,
+ connection logs, queue contents, or event-level timestamps;
+- require universal read access to node logs or databases;
+- instruct nodes to enable debug logging;
+- be required for packet forwarding or consensus validity.
+
+Threats addressed: `TM-NET-03`, `TM-OPS-01`.
+
+### 7.11 Release system
+
+Release signing is outside every runtime role. Release keys MUST NOT exist on
+mix, authority, entry, courier, storage, observer, relay, or general CI
+workers.
+
+The release process MUST produce canonical signed metadata, artifact hashes,
+version and compatibility information, rollback constraints, and provenance.
+Composer and node update verification MUST fail closed. Emergency revocation
+MUST use an authenticated path distinct from ordinary online administration.
+
+Threats addressed: `TM-SUPPLY-01`, `TM-ENDPOINT-01`, `TM-CRYPTO-01`,
+`TM-CRYPTO-02`.
+
+### 7.12 `fog-bridge-*`
+
+An external bridge is never part of the core trust claim. It MUST be a
+separate executable, identity, service descriptor, process, host policy, data
+store, log policy, and threat-model appendix.
+
+It MUST NOT share a process with courier, storage, entry, or mix roles. Its
+output is governed by the external protocol, and FOG cannot conceal metadata
+that the external endpoint reveals.
+
+## 8. Trust-Boundary Interfaces
+
+Every interface MUST have one owning specification, exact framing, maximum
+size, authentication rule, replay rule, timeout, failure class, and test
+vectors.
+
+| ID | Interface | Producer -> consumer | Data class | Owning specification |
+| --- | --- | --- | --- | --- |
+| `IF-01` | Composer export | Composer -> transfer receiver -> relay | `OPAQUE-META` | `FOG-COMPOSER`, `FOG-SX` |
+| `IF-02` | Composer import | relay or controlled medium -> Composer | `PUBLIC-AUTH`, `OPAQUE-META`, `CAPABILITY` | `FOG-COMPOSER` |
+| `IF-03` | Descriptor upload | node -> authorities | `PUBLIC-AUTH` | `FOG-PKI`, `FOG-WIRE` |
+| `IF-04` | Authority vote | authority -> authority | `PUBLIC-AUTH` | `FOG-PKI`, `FOG-WIRE` |
+| `IF-05` | Consensus distribution | authorities or mirrors -> all roles | `PUBLIC-AUTH` | `FOG-PKI` |
+| `IF-06` | Relay submission | relay -> entry | `OPAQUE-META` | `FOG-WIRE`, `FOG-SPHINX-PROFILES` |
+| `IF-07` | Layer forwarding | entry/L1/L2/L3 -> next role | `OPAQUE-META` | `FOG-WIRE`, `FOG-SPHINX-PROFILES` |
+| `IF-08` | Terminal request | L3 -> courier or service | `OPAQUE-META` | `FOG-WIRE`, `FOG-SPHINX-PROFILES`, service contract |
+| `IF-09` | Replica operation | courier <-> replicas; replica <-> replica | `OPAQUE-META` | `FOG-STORAGE`, `FOG-WIRE` |
+| `IF-10` | Anonymous reply | courier/service -> mix route -> entry/relay | `OPAQUE-META`, `CAPABILITY` | `FOG-SPHINX-PROFILES`, `FOG-WIRE` |
+| `IF-11` | Aggregate submission | role -> observer | `AGGREGATE` | `FOG-OBSERVABILITY`, `FOG-WIRE` |
+| `IF-12` | Signed update | release distribution -> role | `PUBLIC-AUTH` | `FOG-UPDATE` |
+| `IF-13` | Local administration | operator -> one role | role-local | deployment profile |
+
+No generic RPC bus, shared event bus, shared SQL database, shared Redis, or
+service mesh identity MAY span these trust boundaries in the core profile.
+
+## 9. Control-Plane Flows
+
+### 9.1 Node admission and descriptor publication
+
+1. An operator creates separate role and node identities using an offline or
+ controlled enrollment procedure.
+2. The operator submits a signed admission request with role, family, layer,
+ address, public keys, supported profiles, and declared infrastructure.
+3. Authorities validate policy and operator-family conflicts.
+4. An admitted node creates an epoch descriptor and signs canonical bytes.
+5. The node submits the descriptor independently to the authority set.
+6. Authorities validate and include eligible descriptors in their votes.
+
+Admission does not imply health, honesty, independence, or permanent
+eligibility. These are separately governed and measured.
+
+### 9.2 Consensus production
+
+1. Authorities exchange authenticated votes and commitments.
+2. Each authority derives canonical topology and network parameters.
+3. A consensus becomes valid only with the configured threshold of signatures
+ over identical canonical bytes.
+4. Current and next key material overlap only for the specified window.
+5. Authorities and mirrors publish signed votes, consensus, and revocations.
+
+FOG-PKI defines deterministic responses to split votes, missing quorum, clock
+skew, stale epochs, rollback, freeze, and equivocation. Consumers MUST NOT
+merge partial views locally.
+
+### 9.3 Consensus consumption by an offline Composer
+
+1. The relay obtains complete consensus from more than one retrieval path
+ where practical.
+2. The relay passes the bytes and available consistency evidence through the
+ controlled import boundary.
+3. The Composer performs canonical parsing, threshold signature validation,
+ epoch and rollback checks, profile checks, and trust-anchor checks.
+4. Only the accepted consensus may drive routes, entry candidates, packet
+ profiles, and traffic parameters.
+5. The Composer persists the highest accepted epoch before exporting work
+ based on it.
+
+An untrusted relay can withhold or replay data and cause denial of service, but
+it MUST NOT be able to make a forged or rolled-back view valid.
+
+## 10. Outbound User Flow
+
+The logical outbound flow is:
+
+1. A Composer application module creates a bounded semantic message.
+2. The Composer stages one authenticated message transition, encrypts the
+ message for the recipient, and atomically persists the advanced state with
+ the exact immutable envelope before that envelope becomes exportable.
+3. The Composer atomically derives the required storage box and capability
+ transition, persists its immutable storage request generation, and only
+ then makes the operation exportable.
+4. The Composer selects a consensus-valid terminal role and one node from each
+ mix layer, obeying operator-family constraints.
+5. The Composer creates the KEMSphinx packet, reply material, and entry-bound
+ opaque submission variants.
+6. The Composer exports a fixed-class work bundle over `IF-01`.
+7. The relay validates only the outer work-bundle contract, queues it, and
+ selects one Composer-authorized entry variant under the current schedule.
+8. The relay sends the opaque variant to the selected entry over `IF-06`.
+9. The entry validates the entry capsule and forwards the bound packet to the
+ authorized layer-1 node.
+10. Each mix performs exactly one transformation, delay, replay check, and
+ forwarding decision.
+11. Layer 3 delivers the terminal packet to the selected courier or native
+ service.
+12. The courier performs the bounded opaque operation and, where applicable,
+ contacts storage replicas through `IF-09`.
+13. A result returns only through the supplied anonymous reply mechanism.
+
+At no point may the relay reconstruct the internal route, the entry change it,
+or a mix interpret the user message.
+
+The exact choice between a complete packet per entry variant and a smaller
+entry capsule bound to a shared packet remains an explicit protocol decision.
+It MUST be resolved with packet-size, replay, fallback, and correlation
+analysis before implementation.
+
+## 11. Retrieval and Reply Flow
+
+FOG does not require direct user-to-user sessions. Retrieval is a Composer-
+constructed anonymous service operation.
+
+1. The relay obtains short-lived return-rendezvous material from eligible
+ entries or maintains an eligible live session under the active profile.
+2. The relay transfers the opaque public or capability-bound rendezvous
+ material to the Composer through `IF-02`.
+3. The Composer validates it against accepted consensus and binds a single-use
+ reply route to a retrieval or write operation.
+4. The outbound operation traverses entry, all mix layers, and the courier.
+5. The courier or service returns one fixed-class response using the supplied
+ single-use reply material.
+6. The reply traverses the consensus-authorized mix route and terminates at a
+ bounded entry rendezvous or eligible live relay session.
+7. The relay stores only the opaque response until expiry or controlled
+ Composer import.
+8. The Composer stages authentication, decryption, deduplication, and message
+ state advancement, then atomically commits all effects before rendering
+ content or scheduling an acknowledgment.
+
+An entry return rendezvous MUST be random, short-lived, bounded, and unrelated
+to a stable global username. It MUST NOT become a durable provider mailbox.
+Exact queueing, polling, retransmission, acknowledgment, and SURB behavior is
+defined by the packet, wire, messaging, and storage specifications.
+
+Empty reads, hits, misses, replies, retries, and acknowledgments MUST fit the
+same declared external traffic classes. A relay MUST continue its configured
+cover and retrieval schedule independently of whether the Composer has a real
+operation pending.
+
+## 12. Cover and Loop Traffic Architecture
+
+Cover generation is a protocol subsystem, not an optional application feature.
+
+- The Composer prepares user-protocol decoys when they require message or
+ storage semantics unavailable to the relay.
+- The blind relay generates network cover and loop traffic using only public
+ consensus and ephemeral local state.
+- Entries process cover submissions identically to real submissions.
+- Mixes generate and process consensus-authorized loop or decoy packets.
+- Couriers, services, and replicas implement indistinguishable bounded cover
+ outcomes defined by their protocol.
+- Nodes export only delayed aggregate loss and health measurements.
+
+The simulator determines cover rate, destination selection, delay, loop,
+retry, polling, and shutdown parameters. Operators MUST NOT tune privacy-
+critical distributions independently outside an authenticated profile.
+
+`FOG-SIMULATION.md` records the first deterministic comparison matrix. It
+confirms that sparse use and the functional PoC do not support anonymity
+claims, and that cover volume, local pool overlap, latency, and long-term
+observation proxies trade different resources. It deliberately selects no
+numeric profile. Loop, polling, retry, queue, degraded-mode, formal observer,
+and trace-driven extensions remain required before parameters are frozen.
+
+If the minimum traffic or cover conditions attached to a claim disappear,
+nodes follow the specified degraded-mode or shutdown policy. They MUST NOT
+silently continue under the stronger claim.
+
+## 13. State Ownership
+
+| Role | Permitted durable state | Forbidden durable state |
+| --- | --- | --- |
+| Composer | encrypted identity, contacts, message state, capabilities, drafts, trust anchors, highest epoch | online session credentials for other roles, node private keys |
+| Relay | encrypted opaque queues, schedule state, temporary entries, return handles, highest relay-checked epoch | plaintext, contact state, mailbox capabilities, internal routes |
+| Authority | descriptors, votes, consensus history, admission and revocation records | user packets, capabilities, data-plane queues |
+| Entry | node configuration, bounded replay-independent ingress state, short-lived opaque return state | durable user accounts, plaintext, internal routes, mailboxes |
+| Mix | epoch keys, replay state, bounded delay queues, local aggregate counters | message state, application data, full routes, user identities |
+| Courier | bounded deduplication, retry and reply state | durable mailboxes, user identity state, plaintext |
+| Store | opaque records, tombstones, expiry and replica state | user identities, plaintext, courier dedup state |
+| Service | explicitly specified minimum opaque service state | unrelated application state, client network identity |
+| Observer | delayed aggregate submissions and published aggregates | event streams, packet identifiers, role secrets |
+
+State schemas MUST include version, ownership, integrity, maximum size,
+retention, migration, backup, restore, corruption, and deletion behavior.
+Copying a database between roles or replicas is not a recovery mechanism.
+
+## 14. Key Ownership
+
+Each narrower protocol specification MUST refine this table into exact key
+lifecycle entries.
+
+| Key class | Sole owning role | Authorized use | Baseline persistence |
+| --- | --- | --- | --- |
+| Pairwise contact roots and handshake identities | Composer | private contact authentication and session establishment | long-term encrypted user state, with profile-specific recovery rules |
+| Ratchet, outbox, deduplication, and conversation state | Composer | atomic message send, retry, receive, and acknowledgment transitions | encrypted mutable user state, non-resumable after stale restore |
+| Directional stream capability and storage outbox state | Composer | rotating box derivation, immutable request generations, reads, writes, tombstones, and receipt validation | encrypted mutable user state, non-resumable after stale restore |
+| Composer state-encryption key | Composer | local authenticated encryption | profile-specific protected storage |
+| Backup or recovery key | user offline recovery domain | restore Composer state | separate from backup ciphertext |
+| Relay queue-sealing key | blind relay | local opaque queue protection | local service-protected storage |
+| Relay ephemeral cover state | blind relay | cover and loop construction | bounded or ephemeral |
+| Node identity key | one online node | descriptor and role authentication | role-local protected storage |
+| Noise link key | one online node | fixed adjacent-link profile | role-local, rotated by profile |
+| Entry capsule key | one entry | open entry-bound submission capsule | epoch-bounded role-local state |
+| Entry return KEMSphinx key | one entry | exactly one terminal reply unwrap for a short-lived rendezvous | epoch-bounded role-local state |
+| Mix KEMSphinx key | one mix | exactly one layer transformation | epoch-bounded role-local state |
+| Terminal KEMSphinx key | one courier or service | open terminal service envelope | epoch-bounded role-local state |
+| Replica envelope key | one storage replica | replica request and response protection | epoch or storage-profile bounded |
+| Replica receipt key | one storage replica | authenticate local durable storage results to the Composer | storage-manifest bounded, separate from envelope, identity, and Noise keys |
+| Storage-at-rest key | one replica operator | defense-in-depth disk or database encryption | deployment-specific |
+| Authority identity key | one authority | authority identity and authenticated recovery | preferably offline or hardware-protected |
+| Authority online vote key | one authority | epoch vote and consensus participation | short-lived or tightly controlled online state |
+| Authority wire key | one authority wire service | authenticated descriptor and authority-peer transport | root-certified bounded online state |
+| Aggregate signing key | one reporting role | authenticate coarse metrics | role-local |
+| Release signing key | offline release domain | sign canonical releases and metadata | offline, never on runtime hosts |
+
+Public consensus contains only public keys and authenticated parameters.
+Private keys MUST NOT be copied through consensus, container images, shared
+volumes, environment templates, logs, or support artifacts.
+
+No role may use a long-term user identity key as a network account, storage
+capability, node identity, transport key, release key, or backup key.
+
+## 15. Network Reachability Policy
+
+Default-deny reachability is part of the architecture.
+
+| Source | Permitted destinations | Explicitly forbidden destinations |
+| --- | --- | --- |
+| Composer | none | every network target |
+| Relay | consensus mirrors, eligible entries, explicitly configured local transfer interface | mixes, courier, storage, external bridges, Internet proxy targets |
+| Authority | peer authorities, descriptor submitters, consensus publication endpoints, local administration | user data plane, storage records |
+| Entry | eligible relays, layer-1 nodes, bounded reply-route peers required by profile | layer 2, layer 3, storage, public Internet |
+| Layer 1 mix | entries and layer-2 nodes | relay, layer 3, storage, public Internet |
+| Layer 2 mix | layer-1 and layer-3 nodes | relay, entry, storage, public Internet |
+| Layer 3 mix | layer-2 and terminal courier/service nodes | relay, entry, storage, public Internet |
+| Courier | layer-3 or authorized reply-route mix peers, eligible replicas | relay, Composer, public Internet |
+| Store | eligible couriers and replica peers | Composer, relay, entry, ordinary mixes, public Internet |
+| Observer | aggregate-reporting roles and publication endpoint | packet interfaces, role databases |
+| Bridge | explicitly declared FOG terminal and external endpoint | all undeclared core interfaces |
+
+The reply protocol MAY require a terminal role to connect to a
+consensus-authorized first reply hop that differs from the forward table. That
+exception MUST be explicit in `FOG-SPHINX-PROFILES`, constrained by role and
+epoch, and tested as part of the firewall policy.
+
+Management access is a separate operator-local boundary. No central
+management credential may administer all authorities, all mix layers, the
+courier, and the replica set in a claim-bearing deployment.
+
+## 16. Co-Location and Operator Separation
+
+### 16.1 Functional PoC
+
+The local PoC MAY place separate containers on one host and MAY use simulated
+authority or storage fixtures. It MUST still use separate executables, service
+users, state paths, key files, ports, and default-deny container networks.
+
+PoC co-location invalidates operator-independence, infrastructure-diversity,
+and production anonymity claims.
+
+`FOG-LOCAL-POC.md` and `../deploy/podman/topology.json` refine this into the
+first deployment contract. The Composer and authority fixtures are
+networkless. Relay, entry, one mix in each fixed layer, courier, and four
+storage fixtures use only internal pairwise networks for `IF-06` through
+`IF-09`. The contract forbids host networking, published ports, shared
+writable volumes, shared secret scopes, and missing containment controls. No
+Compose manifest is generated until role fixtures exist.
+
+### 16.2 Alpha
+
+An alpha profile MUST use:
+
+- at least three authorities with a 2-of-3 quorum;
+- three mix layers with at least two independently operated mixes per layer;
+- at least four independently operated storage replicas;
+- separate entry, mix, courier, and storage role identities;
+- documented operator-family, provider, ASN, location, and administrative
+ relationships;
+- no route containing the same operator family twice.
+
+One operator MAY run more than one role only when the relationship is declared,
+route policy accounts for it, and the relevant security claim explicitly
+allows it. One process or private key MUST NOT implement more than one role.
+
+### 16.3 Claim-bearing production profile
+
+The preferred initial topology is three mix nodes per layer. Authority,
+entry, mix, courier, storage, observer, build, and release administration
+SHOULD be organizationally separated where practical.
+
+No provider account, orchestration control plane, backup service, monitoring
+credential, or CI system SHOULD control enough nominal operators to defeat the
+claim. Concealed common control remains a documented residual risk.
+
+## 17. Failure and Degraded Modes
+
+| Condition | Required architectural response |
+| --- | --- |
+| Consensus signature or canonical parse failure | reject and retain last safely usable state only within its validity |
+| Stale or rolled-back consensus | stop new route construction; require authenticated recovery |
+| Authority quorum failure | no locally synthesized consensus; continue only under explicitly valid prior epoch rules |
+| Entry failure | choose only another pre-authorized opaque variant under randomized bounded retry policy |
+| Mix connection failure | bounded backoff; no layer skip or deterministic emergency route |
+| Replay state unavailable | stop affected mix processing until safe recovery or specified fresh epoch |
+| Cover process failure | leave the affected unobservability profile and follow explicit shutdown/degraded policy |
+| Queue saturation | bounded shedding without detailed remote oracle or amplification |
+| Courier or replica timeout | bounded randomized retry through the defined protocol; no direct client fallback |
+| Replica loss | follow specified quorum or erasure behavior; never fabricate successful durability |
+| Clock uncertainty outside bound | reject time-sensitive new state and surface coarse local fault |
+| Update verification failure | retain last verified non-revoked version or stop if policy requires it |
+| State corruption | quarantine state, avoid secret-bearing diagnostics, and use authenticated recovery |
+
+Detailed error codes may exist inside a trusted local process boundary for
+testing. Remote peers receive only bounded protocol outcomes that do not expose
+parsing, capability, record-existence, or route oracles.
+
+## 18. Configuration, Build, and Update Boundaries
+
+Configuration MUST be role-specific and schema-validated. A deployment tool
+MAY generate multiple role configurations, but the generated runtime artifacts
+MUST contain only the public information and secrets required by that role.
+
+Runtime services MUST use:
+
+- a dedicated unprivileged account;
+- a role-specific read-only executable and configuration;
+- one role-specific writable state directory;
+- no shared writable source or configuration checkout;
+- explicit network allowlists;
+- bounded resource controls;
+- disabled core dumps and privacy-unsafe debug modes;
+- local secret injection that does not place secrets in command arguments or
+ container images.
+
+Build, release signing, consensus signing, node operation, and user identity
+management are separate authorities. A successful CI build does not authorize
+a release, a release does not authorize a network epoch, and an epoch does not
+authorize user messages.
+
+### 18.1 Cost-minimal build and packaging profile
+
+One release build MUST compile all required role executables once per supported
+operating-system and architecture target. Nodes and operators MUST reuse those
+verified artifacts; they MUST NOT require per-node or per-operator compilation.
+The build SHOULD share dependency, object, and module caches across role
+executables.
+
+The functional fixture and local alpha laboratory MAY use one immutable
+digest-pinned image containing multiple fixture executables, provided every
+container activates exactly one role and preserves separate configuration,
+service identity, state, secrets, and network policy. This packaging exception
+does not permit a multi-role process.
+
+A distributed alpha or claim-bearing deployment SHOULD assemble one minimal
+image per runtime role from the already compiled artifact set. Role images
+SHOULD share identical OCI base layers so registries and hosts deduplicate
+storage and transfer. Image assembly MUST NOT trigger a separate compilation
+for every image or node.
+
+The supported build matrix MUST contain only platforms required by current
+deployment or evidence gates. Independent reproducible rebuilds are release
+verification evidence and MAY reuse the same source and pinned toolchain; they
+are not required for routine startup of each node.
+
+## 19. Repository and Module Shape
+
+The future implementation repository SHOULD begin with this logical layout.
+Exact language-specific names MAY vary without changing dependency direction.
+
+```text
+fog/
+ cmd/
+ fog-compose/
+ fog-sx-send/
+ fog-sx-receive/
+ fog-client-relay/
+ fog-authority/
+ fog-entry/
+ fog-mix/
+ fog-courier/
+ fog-store/
+ fog-observer/
+ protocol/
+ encoding/
+ pki/
+ wire/
+ sphinx/
+ messaging/
+ storage/
+ composer/
+ sx/
+ roles/
+ authority/
+ entry/
+ mix/
+ courier/
+ store/
+ observer/
+ clientrelay/
+ sdk/
+ client/
+ composer/
+ sim/
+ specs/
+ testvectors/
+ tests/
+ conformance/
+ integration/
+ fault/
+ topology/
+ deploy/
+ podman/
+ ops/
+```
+
+Dependency direction MUST be:
+
+```text
+cmd -> one role -> protocol packages
+sdk ------------> protocol packages
+sim ------------> protocol models and independent simulation models
+tests ----------> public contracts and built executables
+```
+
+Protocol packages MUST NOT import role implementations, network listeners,
+databases, container tooling, or operator configuration. One role package MUST
+NOT import another role's implementation. Cross-role behavior occurs only
+through versioned protocol interfaces.
+
+The public SDK MUST expose message and packet construction contracts without
+exposing node private APIs. Generic `utils`, shared mutable singletons, a
+universal database package, and an in-process plugin bus are forbidden
+substitutes for explicit boundaries.
+
+The following MUST NOT be split yet:
+
+- separate source repositories for every role;
+- server daemons for `fog-drop`, `fog-mailbox`, and `fog-im`;
+- a generic external bridge framework inside core nodes;
+- operator-selectable cryptographic plugin systems;
+- separate databases or queues where a role currently needs no durable state.
+
+## 20. Architectural Verification
+
+Before the local PoC, the repository MUST support or define tests for:
+
+- one executable activating only one role;
+- dependency rules preventing role-to-role implementation imports;
+- configuration schema rejection of multi-role or unknown-critical settings;
+- default-deny reachability for every row in the network policy table;
+- inability of Composer images to create or receive network traffic;
+- absence of shared writable volumes and private key files across roles;
+- fixed packet-class behavior across all native applications;
+- complete traversal of entry and all mix layers;
+- replay-state loss and fail-closed restart behavior;
+- voucher consume-once behavior and atomic ratchet, outbox, deduplication,
+ inbox, and acknowledgment transactions;
+- exact message-envelope and storage-request retry layering: immutable
+ courier-envelope bytes per request generation with fresh KEMSphinx, route,
+ entry, rendezvous, and reply material per transmission;
+- deterministic storage shards, disjoint intermediates, receipt quorum,
+ empty-read non-advancement, tombstone precedence, and non-resurrection;
+- exact Composer bundle headers, hostile import limits, commit-before-effect,
+ external-anchor reconciliation, non-resumable recovery, and update floors;
+- exact FOG-SX object and frame headers, fixed profile tuple, size padding,
+ CRC domains, FEC and conflict budgets, no-ACK behavior, and physical
+ direction fixtures;
+- consensus stale, rollback, split, and equivocation scenarios;
+- queue, parser, retry, CPU, memory, connection, and storage bounds;
+- log and metrics schemas that reject prohibited data classes;
+- compromise fixtures showing the information available to each isolated role;
+- update signature, version, rollback, and revocation behavior;
+- deterministic conformance vectors for every trust-boundary interface.
+
+Tests MUST observe public contracts and externally visible behavior, not reach
+through trust boundaries to share internal state.
+
+## 21. Threat Traceability
+
+| Threat | Primary architectural controls |
+| --- | --- |
+| `TM-NET-01` | uniform packet classes, relay scheduling, cover subsystem, stratified mixes |
+| `TM-NET-02` | independent retrieval schedule, rotating capabilities, bounded rendezvous, storage separation |
+| `TM-NET-03` | loop health, degraded-mode gate, bounded retries, no bypass |
+| `TM-NET-04` | per-mix replay state, single-use reply material, idempotent terminal state |
+| `TM-NET-05` | authenticated KEMSphinx processing, terminal validation, uniform failures |
+| `TM-NET-06` | complete consensus, fixed profiles, application-independent core behavior |
+| `TM-PKI-01` | permissioned admission, family declarations, route constraints |
+| `TM-PKI-02` | threshold consensus, monotonic Composer state, consistency evidence |
+| `TM-PKI-03` | distinct authorities, quorum rules, offline recovery, deterministic failure |
+| `TM-ROLE-01` | blind relay, entry capsules, Composer route authority, no direct fallback |
+| `TM-ROLE-02` | one fixed mix layer per process, family-separated routes, role-local keys |
+| `TM-ROLE-03` | courier/replica separation, opaque commands, independent replicas |
+| `TM-ENDPOINT-01` | networkless Composer, narrow devices, encrypted state, signed updates |
+| `TM-ENDPOINT-02` | minimal transfer adapter, bounded formats, no reverse FOG-SX path |
+| `TM-ENDPOINT-03` | role-owned state, separate backup keys, no database copying |
+| `TM-APP-01` | Composer-side application state, bounded authenticated rendering, no active content |
+| `TM-OPS-01` | separate observer, aggregate-only interface, prohibited data classes |
+| `TM-SUPPLY-01` | offline release authority, provenance, signed updates, role-specific artifacts |
+| `TM-CRYPTO-01` | sole key owners, purpose separation, lifecycle refinement requirement |
+| `TM-CRYPTO-02` | consensus-authorized suites, no plugin negotiation or downgrade |
+| `TM-AVAIL-01` | bounds at every interface, non-amplification, quotas, explicit degraded modes |
+
+Every later specification MUST reference the applicable threat IDs and
+architecture invariants. If it changes a trust boundary or information flow,
+this document and the threat model MUST be updated before implementation.
+
+## 22. Open Architectural Protocol Contracts
+
+This architecture intentionally leaves the following to narrower reviewed
+specifications:
+
+- the exact entry submission capsule and packet binding;
+- short-lived return rendezvous and offline Composer import mechanics;
+- activation of an exact numeric message profile after the structural
+ `FOG-MESSAGING` contract and its non-active PQXDH, Triple Ratchet, and
+ ML-KEM Braid candidate pass byte-exact integration, vectors, implementation
+ review, and independent review;
+- the exact reviewed entry and mutual Noise or PQNoise suites and numeric
+ wire-profile parameters within `FOG-WIRE-1`; X-Wing is the leading KEM to
+ evaluate, not an active profile;
+- activation of a final `FOG-SPHINX-1` primitive suite after the fixed
+ structural profile and calculated candidate in `FOG-SPHINX-PROFILES.md` pass
+ benchmarks, vectors, simulation, and independent review;
+- activation of an exact numeric storage profile after the structural
+ `FOG-STORAGE` contract and its non-active narrow BACAP/Pigeonhole candidate
+ pass primitive review, receipt analysis, geometry, vectors, simulation, and
+ independent review;
+- activation of exact Composer MicroVM and Portable profiles after the
+ structural `FOG-COMPOSER` contract and its Linux vault, Qubes, Portable, and
+ TUF candidates pass platform, anchor, fault, recovery, and independent
+ review;
+- cover, loop, delay, retry, retrieval, and shutdown distributions;
+- activation of one exact numeric FOG-SX joint profile after the structural
+ `FOG-SX` contract and its non-active RaptorQ, Reed-Solomon, QR, Lightpipe,
+ and MIDI candidates pass implementation, license and IPR, resource, vector,
+ hardware-direction, and independent review;
+- exact aggregate metrics and suppression thresholds;
+- implementation languages, reviewed libraries, and activation evidence for
+ the non-active cryptographic candidates in `FOG-CRYPTO-SUITES.md`.
+
+These are explicit design dependencies. No daemon implementation may resolve
+them through undocumented behavior.
+
+## 23. References
+
+- FOG threat model: `FOG-THREAT-MODEL.md`
+- FOG public key infrastructure: `FOG-PKI.md`
+- FOG wire protocol: `FOG-WIRE.md`
+- FOG Sphinx profile framework: `FOG-SPHINX-PROFILES.md`
+- FOG messaging protocol: `FOG-MESSAGING.md`
+- FOG storage protocol: `FOG-STORAGE.md`
+- FOG Composer protocol: `FOG-COMPOSER.md`
+- FOG simplex transfer protocol: `FOG-SX.md`
+- FOG observability protocol: `FOG-OBSERVABILITY.md`
+- FOG cryptographic suite evaluation: `FOG-CRYPTO-SUITES.md`
+- FOG traffic and topology simulation: `FOG-SIMULATION.md`
+- FOG local Podman PoC: `FOG-LOCAL-POC.md`
+- Katzenpost mix network specification:
+ <https://katzenpost.network/docs/specs/mixnet/>
+- Katzenpost public key infrastructure specification:
+ <https://katzenpost.network/docs/specs/pki/>
+- Katzenpost wire protocol specification:
+ <https://katzenpost.network/docs/specs/wireprotocol/>
+- Katzenpost Pigeonhole protocol specification:
+ <https://katzenpost.network/docs/specs/pigeonhole/>
+- Piotrowska et al., *The Loopix Anonymity System*:
+ <https://www.usenix.org/conference/usenixsecurity17/technical-sessions/presentation/piotrowska>
+- Infeld et al., *Echomix: a Strong Anonymity System with Messaging*:
+ <https://arxiv.org/abs/2501.02933>
+- Noise Protocol Framework:
+ <https://noiseprotocol.org/noise.html>
+
+These references inform role separation, stratified mixing, consensus,
+transport, reply, and storage boundaries. FOG requires its own protocol
+profiles, conformance evidence, simulation, deployment evidence, and review.
diff --git a/docs/FOG-COMPOSER.md b/docs/FOG-COMPOSER.md
new file mode 100644
index 0000000..b517db5
--- /dev/null
+++ b/docs/FOG-COMPOSER.md
@@ -0,0 +1,1677 @@
+# FOG Composer
+
+Status: Draft 0.1
+
+Date: 2026-08-08
+
+## 1. Purpose
+
+This document defines `FOG-COMPOSER`, the networkless endpoint, local-state,
+transfer, recovery, and update-verification contract for FOG native services.
+
+It fixes the common Composer security boundary, MicroVM and Portable
+deployment profiles, process separation, authenticated encrypted vault,
+transaction and rollback rules, hostile import handling, committed export
+bundles, identity-safe recovery, update verification, local rendering,
+resource limits, and conformance gates.
+
+It also records four non-active implementation candidates:
+
+- `FOG-COMPOSER-CANDIDATE-LINUX-VAULT-1` for a Linux read-only system image,
+ LUKS2 defense-in-depth volume encryption, a transactional embedded
+ database, and object-level authenticated encryption;
+- `FOG-COMPOSER-CANDIDATE-MICROVM-QUBES-1` for a Qubes-style networkless VM
+ with narrowly allowlisted qrexec transfer services;
+- `FOG-COMPOSER-CANDIDATE-PORTABLE-LINUX-1` for a signed read-only Linux image
+ on dedicated physically offline hardware;
+- `FOG-COMPOSER-CANDIDATE-UPDATE-TUF-1` for offline update metadata derived
+ from The Update Framework.
+
+These candidates have no active numeric profile IDs, do not select final
+libraries or cryptographic parameters, are not authorized for public release,
+and do not establish deployed endpoint-security claims.
+
+The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, and MAY describe
+normative requirements in the sense of BCP 14 when they appear in uppercase.
+
+## 2. Scope
+
+`FOG-COMPOSER` owns:
+
+- the networkless Composer runtime and its local privilege boundaries;
+- common, MicroVM, Portable, and lower-assurance transfer profiles;
+- booted-image verification requirements visible to the Composer;
+- encrypted mutable state, key wrapping, object protection, and state
+ migration;
+- local atomic transactions spanning messaging, storage, PKI, imports,
+ exports, recovery, and application state;
+- local state commitments and optional external monotonic anchors;
+- fixed Composer bundle framing and direction-specific record allowlists;
+- import quarantine, complete validation, deduplication, and state release;
+- transactional export creation and duplicate-export behavior;
+- identity recovery packages and non-resumable restored sessions;
+- offline release and update verification on Composer systems;
+- safe local rendering and native application module boundaries;
+- local retention, deletion, diagnostic, and resource-limit behavior;
+- Composer-specific conformance and fault-injection evidence.
+
+This document does not own:
+
+- message handshake, ratchet, envelope, acknowledgment, or fragmentation
+ cryptography;
+- storage capabilities, replica envelopes, receipts, retention, or polling;
+- KEMSphinx packet or SURB construction;
+- adjacent online Noise links or blind-relay queue behavior;
+- FOG-PKI consensus production, authority recovery, or transparency proofs;
+- FOG-SX framing, FEC, physical signaling, or optical hardware;
+- entry capsule and return-rendezvous constructions;
+- release-repository production, signing ceremonies, or build provenance;
+- a native multi-device protocol or automatic account recovery service.
+
+Those contracts belong to `FOG-MESSAGING`, `FOG-STORAGE`,
+`FOG-SPHINX-PROFILES`, `FOG-WIRE`, `FOG-PKI`, `FOG-SX`, the entry and return
+specifications, a future `FOG-UPDATE` release contract, and future
+multi-device work.
+
+## 3. Security Boundary and Threats
+
+### 3.1 Assets
+
+The Composer holds the highest-value user assets in FOG:
+
+- message plaintext, drafts, permitted attachments, and rendered history;
+- pairwise identity roots, handshake identities, prekeys, ratchets, and
+ skipped-message keys;
+- storage read and write capabilities, recovery tombstones, and outboxes;
+- contacts, private labels, verification decisions, and conversation state;
+- PKI trust anchors, accepted epochs, checkpoints, manifests, and
+ equivocation evidence;
+- KEMSphinx routes, ephemeral secrets, SURBs, reply tokens, and pending
+ network work;
+- vault, object, transfer-pairing, backup, recovery, and local anchor keys;
+- installed release state, trusted release roots, and rollback floors.
+
+Compromise of an unlocked Composer can expose or alter all local assets. No
+storage, boot, VM, or transfer mechanism can preserve confidentiality against
+an attacker that controls the code currently using the plaintext and keys.
+
+### 3.2 Adversaries
+
+The contract considers:
+
+- theft or forensic copying of powered-off storage;
+- malicious, malformed, replayed, truncated, reordered, or oversized import;
+- a compromised blind relay, transfer receiver, removable medium, QR reader,
+ FOG-SX decoder, or update distributor;
+- partial database corruption, torn writes, power failure, disk-full faults,
+ and stale filesystem snapshots;
+- rollback or cloning of a complete internally consistent Composer vault;
+- a hostile MicroVM host, hypervisor, firmware, peripheral, DMA device, boot
+ chain, or system update;
+- malicious contacts and authenticated but adversarial message content;
+- physical observation, evil-maid access, side channels, and secret remnants;
+- dependency, compiler, build, release-key, or update-metadata compromise.
+
+### 3.3 Trust distinctions
+
+Object-level authenticated encryption protects stored object confidentiality
+and integrity under its exact key assumptions. It does not prove freshness.
+
+A hash-chained local journal detects missing, reordered, partially restored,
+or corrupted state relative to the latest state still available locally. It
+cannot detect replacement of the complete vault, journal, and keys by an older
+coherent copy.
+
+Complete rollback detection requires a monotonic anchor outside the rollback
+domain. A virtual TPM controlled by the same hostile VM host is not independent
+of that host. A counter alone also does not automatically bind the intended
+state commitment unless the selected anchor protocol proves that binding.
+
+Networklessness prevents direct network access by the guest or portable
+runtime. It does not prevent a hostile host, firmware, peripheral, or human
+from observing or modifying the endpoint.
+
+## 4. Protocol Invariants
+
+### COMPOSER-INV-01: No network interface
+
+A conforming Composer has no network adapter, route, network namespace access,
+socket activation, proxy, update proxy, loopback service, HTTP server, RPC
+server, or plugin listener. A convenience mode with networking is not a FOG
+Composer profile.
+
+### COMPOSER-INV-02: One active mutable instance
+
+One Composer identity vault has exactly one active mutable instance. Copying a
+vault, VM private volume, database, USB state partition, or live backup does
+not create a second device. Any suspected clone freezes affected ratchets,
+capabilities, prekeys, outboxes, and monotonic state.
+
+### COMPOSER-INV-03: Random data keys, human unlock
+
+Bulk state is encrypted under random vault and object keys. A passphrase or
+recovery phrase is processed only by the profile's reviewed memory-hard KDF to
+unlock or rewrap random key material. It is never used directly as an AEAD
+key, identity key, ratchet seed, storage capability, or backup key.
+
+### COMPOSER-INV-04: Every sensitive object is authenticated
+
+Identity, contact, draft, message, ratchet, capability, outbox, inbox,
+deduplication, PKI monotonic, recovery, and update state has object-level
+authenticated encryption or an equally reviewed authenticated container.
+Whole-volume encryption is defense in depth and is not accepted as the sole
+object-integrity control.
+
+### COMPOSER-INV-05: Persist and anchor before effect
+
+A security-critical transition is not externally exportable and its plaintext
+is not renderable until the complete local transaction is durable. Where the
+profile claims full rollback detection, the corresponding external monotonic
+anchor transition must also be durable before export or rendering.
+
+### COMPOSER-INV-06: Local chain is not full anti-rollback
+
+Documentation and UI MUST distinguish local consistency verification from
+independent monotonic anchoring. A self-contained vault without an external
+anchor MUST NOT claim detection of a complete coherent rollback.
+
+### COMPOSER-INV-07: Every import is hostile
+
+Filename, label, QR presentation, media filesystem, MIME type, transport
+checksum, FEC result, relay origin, and operator statement confer no
+authenticity. Complete bounded parsing and the owning inner cryptographic
+verification occur before state transition or rendering.
+
+### COMPOSER-INV-08: Export contains committed opaque work only
+
+An export bundle contains only already committed public objects or opaque
+protocol work. It never contains message plaintext, drafts, identity private
+keys, contact labels, ratchet state, capability roots, database keys, backup
+keys, crash diagnostics, or a long-term Composer signature visible to the
+relay.
+
+### COMPOSER-INV-09: Transfer signatures do not create a public identity
+
+FOG does not sign relay-facing bundles with a long-term user or Composer key.
+Each inner object supplies its owning authentication. A local transfer-pairing
+authenticator MAY reject random injection but does not replace inner
+verification and does not become a remote network identity.
+
+### COMPOSER-INV-10: Recovery never silently resumes live state
+
+An identity recovery package can preserve explicitly allowed long-term
+identity and contact verification material. Restored live ratchets,
+capability streams, prekeys, reply tokens, outboxes, and deduplication windows
+remain frozen. They are replaced through authenticated recovery transitions,
+not resumed from a stale snapshot.
+
+### COMPOSER-INV-11: Update verification is offline and monotonic
+
+An update installs only after threshold signature, metadata chain, target
+hash, target length, platform, compatibility, expiry, version, and rollback
+floor validation. No online fetch, local administrator override, unsigned
+emergency image, or boot failure authorizes a downgrade.
+
+### COMPOSER-INV-12: Immutable runtime image
+
+The booted operating-system and Composer image are read-only and verified by a
+root authenticated outside that mutable image. Writable application state,
+temporary data, logs, and update staging cannot replace executable content.
+
+### COMPOSER-INV-13: No active imported content
+
+Initial native applications render bounded plain text and fixed local UI
+objects only. HTML, scripts, macros, fonts, office files, PDFs, media codecs,
+shell commands, desktop launchers, and automatic external resource loading are
+not valid message content.
+
+### COMPOSER-INV-14: High-assurance paths are physically directional
+
+The high-assurance export and import paths use separate transmit-only and
+receive-only mechanisms. A removable device alternated between online and
+offline systems is a named lower-assurance profile, never an invisible
+fallback.
+
+### COMPOSER-INV-15: No secret-bearing diagnostics
+
+Logs, metrics, crash dumps, support bundles, command arguments, environment
+variables, shell history, swap, hibernation, thumbnails, previews, clipboard,
+and generic desktop indexes contain no Composer secrets or plaintext.
+
+### COMPOSER-INV-16: No runtime extension mechanism
+
+The Composer loads no third-party plugin, interpreted script, external
+renderer, generic parser, dynamic protocol module, or operator-selected crypto
+provider. New functionality requires a reviewed release and an authenticated
+profile transition.
+
+## 5. Deployment Profiles
+
+### 5.1 Common profile
+
+Every Composer profile MUST:
+
+- boot an authenticated read-only software image;
+- omit or disable all network and radio devices and drivers;
+- use one dedicated authenticated encrypted mutable vault;
+- separate import quarantine and export spool from active vault state;
+- disable swap, hibernation, core dumps, automatic crash reporting, previews,
+ indexing, and host clipboard integration;
+- mount no internal disk or general removable filesystem automatically;
+- expose only the minimum display, human input, import, export, state, and
+ optional monotonic-anchor devices;
+- enforce the exact bundle profiles, limits, and direction allowlists;
+- require explicit human unlock and explicit update or recovery ceremonies;
+- show the current assurance profile and lost assumptions locally.
+
+### 5.2 MicroVM profile
+
+The MicroVM definition contains no virtual NIC. Network absence is enforced at
+the hypervisor configuration, guest kernel configuration, process sandbox,
+and conformance-test levels.
+
+Host integration is limited to:
+
+- a minimal display path;
+- explicit keyboard and pointing input;
+- one bounded import data channel;
+- one separately authorized bounded export data channel;
+- one dedicated mutable state block device;
+- an optional external monotonic-anchor interface.
+
+Shared directories, host filesystem mounts, arbitrary qrexec, drag-and-drop,
+clipboard, audio, camera, USB passthrough, generic guest agents, shell
+services, and bidirectional device forwarding are forbidden.
+
+The host and hypervisor remain inside the endpoint trust assumption. A
+MicroVM profile can reduce accidental network exposure and contain some
+application failures, but cannot protect unlocked memory or execution from a
+host that can inspect or replace the guest.
+
+The Qubes candidate uses a dedicated no-NetVM qube and two exact qrexec
+services with fixed direction and byte bounds. General qrexec command
+execution, file-copy services, URL opening, clipboard, and update proxy access
+remain denied. Qubes is an integration candidate, not a runtime dependency or
+an automatic security claim.
+
+### 5.3 Portable profile
+
+The Portable profile boots signed immutable media on a physically offline
+computer. Its kernel and initramfs omit network, Bluetooth, cellular, NFC,
+Thunderbolt networking, and unnecessary radio drivers. Firmware setup and
+physical switches disable available radios where supported.
+
+It MUST:
+
+- verify the bootloader, kernel, initramfs, command line, root-image digest,
+ and Composer release identity before vault unlock;
+- use a read-only verified root image and a separate encrypted mutable state
+ partition;
+- refuse automatic internal-disk, network-share, and foreign-filesystem
+ mounting;
+- use dedicated receive-only and transmit-only transfer devices in its
+ high-assurance form;
+- keep Composer state media away from online machines;
+- warn locally when Secure Boot, measured boot, immutable-root verification,
+ external anchoring, or physical directionality is absent.
+
+Portable means the signed system and encrypted state can be carried. It does
+not mean the same active state may be cloned or used concurrently. A profile
+that binds rollback protection to one machine TPM is machine-bound even if its
+boot media is removable.
+
+### 5.4 Portable shuttle profile
+
+`PORTABLE_SHUTTLE` permits one explicitly labeled removable transfer medium to
+move opaque bundles between online and offline systems. It is lower assurance
+because the online system can attack the medium controller, filesystem, and
+subsequent offline parser and because the medium provides a physical return
+channel.
+
+This profile still requires the fixed Composer bundle parser, separate import
+quarantine, no automatic execution, no general file browsing, and complete
+inner authentication. It MUST NOT inherit the high-assurance simplex or
+peripheral-compromise claim.
+
+### 5.5 Claim matrix
+
+| Property | MicroVM | Portable high assurance | Portable shuttle |
+| --- | --- | --- | --- |
+| Composer process has no network | required | required | required |
+| Host compromise protection | not claimed | not applicable while dedicated offline hardware is honest | not claimed for online transfer host |
+| Read-only verified system image | required | required | required |
+| Separate directional transfer hardware | profile-dependent | required | absent by definition |
+| Complete rollback detection | only with an anchor outside the hostile host | only with independent anchor | only with independent anchor |
+| Physical peripheral isolation | host-dependent | required and measured | weakened |
+| Endpoint compromise protection while unlocked | not claimed | not claimed | not claimed |
+
+## 6. Process and Module Architecture
+
+### 6.1 Security domains
+
+The Composer image contains these local domains:
+
+1. `fog-compose`: the only process that unlocks vault keys, performs protocol
+ state transitions, and renders authenticated plaintext;
+2. import decoder: an unprivileged sandbox that reads one raw transfer stream,
+ validates only outer framing and limits, and writes one quarantine object;
+3. export encoder: an unprivileged sandbox that reads one already sealed
+ opaque export and drives one transmit-only backend;
+4. update verifier: a maintenance environment that has release roots and
+ inactive image access but no unlocked Composer vault;
+5. optional anchor adapter: a minimal process or device interface that exposes
+ only the profile's monotonic prepare, advance, and read operations.
+
+The import decoder does not receive vault keys, identity state, contact state,
+message plaintext, network configuration, a shell, or writable executable
+paths. Its output remains untrusted when `fog-compose` opens it.
+
+The export encoder cannot query the vault or create new protocol work. It can
+read only one immutable export spool item selected by `fog-compose` and cannot
+write to import quarantine.
+
+### 6.2 Internal modules
+
+Inside the `fog-compose` trust domain, responsibilities remain explicit:
+
+```text
+ui
+ -> native applications
+ -> messaging and storage coordinators
+ -> transaction service
+ -> encrypted vault
+
+import coordinator -> protocol verifiers -> transaction service
+export coordinator -> committed protocol outbox -> export spool
+PKI verifier -------^ |
+anchor coordinator ---------------------------^
+```
+
+The initial implementation SHOULD use modules named by responsibility:
+
+- `composer/vault`: key hierarchy, encrypted objects, schema, transactions;
+- `composer/anchor`: state commitments and monotonic-anchor protocol;
+- `composer/import`: bundle validation, quarantine, deduplication, dispatch;
+- `composer/export`: committed selection, sealing, spool lifecycle;
+- `composer/update`: trusted metadata and installed-version state;
+- `composer/recovery`: recovery package creation and restore freeze;
+- `composer/ui`: safe presentation and explicit user decisions;
+- `apps/drop`, `apps/mailbox`, and `apps/im`: native state machines only.
+
+Protocol modules do not import UI, filesystem, database, qrexec, removable
+media, or platform code. Platform adapters do not implement messaging,
+storage, PKI, or cryptographic state transitions.
+
+### 6.3 What not to split
+
+The initial implementation does not create:
+
+- separate network services for native applications;
+- one database per application;
+- a generic plugin host or IPC bus;
+- a background indexing or search service with plaintext access;
+- a universal crypto, filesystem, archive, or document adapter;
+- concurrent writable Composer processes.
+
+One transaction owner and one encrypted database simplify the required
+cross-layer atomic commits. Process separation is used only where it removes
+raw transfer or update parsing from the vault-bearing process.
+
+## 7. Boot and Runtime Hardening
+
+### 7.1 Verified immutable image
+
+The profile authenticates the complete boot path and one immutable root-image
+digest. The Linux candidate uses a signed boot artifact and `dm-verity` for
+read-only block verification. The authenticated root digest must be inside the
+signed boot chain, not supplied by mutable kernel arguments or the state
+volume.
+
+Verification failure stops before vault unlock. An integrity error after boot
+locks the vault, produces no export, and enters recovery. Ignore-corruption and
+continue-on-verification-failure modes are forbidden.
+
+### 7.2 Writable mounts
+
+The runtime permits only:
+
+- the dedicated encrypted state volume;
+- a bounded encrypted or memory-backed import quarantine;
+- a bounded export spool containing opaque committed bundles;
+- bounded memory-backed temporary directories;
+- explicit update staging only in maintenance mode.
+
+Executable, setuid, device, and interpreter behavior is disabled on mutable
+mounts where the platform supports it. Imported filenames never become local
+paths. The Composer does not traverse a foreign filesystem supplied by a
+transfer medium.
+
+### 7.3 Runtime controls
+
+The active Composer profile requires:
+
+- no swap or hibernation;
+- disabled core dumps and process-memory crash capture;
+- locked-down debugging, tracing, performance counters, and ptrace;
+- no shell or package manager in the user session;
+- no automatic login or vault unlock;
+- strict process, file-descriptor, memory, CPU, and disk quotas;
+- default-deny device and syscall policy, including network socket creation;
+- memory-backed plaintext staging with bounded lifetime;
+- explicit lock on suspend, display loss, anchor loss, or integrity fault.
+
+Memory locking and explicit zeroization are best-effort implementation
+controls. They do not prove that compilers, kernels, caches, firmware, DMA,
+hibernation remnants, or physical memory retained no copy.
+
+## 8. Vault and Key Hierarchy
+
+### 8.1 Vault layers
+
+The Composer uses both:
+
+1. full-volume encryption to hide filesystem metadata, database pages,
+ journals, temporary files, and free space while powered off;
+2. object-level authenticated encryption for every sensitive logical record.
+
+The Linux candidate evaluates LUKS2 for layer 1. It does not rely on ordinary
+sector encryption to authenticate logical records. Any LUKS2 integrity mode
+requires separate maturity, performance, recovery, and power-failure review.
+
+### 8.2 Key hierarchy
+
+The minimum hierarchy is:
+
+```text
+human unlock secret
+ -> profile-fixed memory-hard KDF
+ -> unlock KEK
+ -> unwrap random vault key
+ -> profile-fixed KDF/exporter
+ -> identity-object key epoch
+ -> contact-object key epoch
+ -> messaging-state key epoch
+ -> storage-state key epoch
+ -> PKI-state key epoch
+ -> draft/content key epoch
+ -> outbox/import/export key epoch
+ -> local-state-authentication key epoch
+```
+
+The backup or recovery key hierarchy is generated independently. It never
+derives from the live vault key, a contact root, message ratchet, storage
+capability, transfer-pairing key, release key, or monotonic-anchor key.
+
+The unlock KDF stores its algorithm identifier, salt, memory cost, time cost,
+parallelism, and output length in authenticated keyslot metadata. Parameters
+are benchmarked per supported hardware class and may be raised through a
+versioned rewrap without reencrypting all logical objects.
+
+The deployment profile states whether volume unlock and object-vault unlock
+use one human secret or separate factors. If one human secret is used, each
+layer has independent salts, context, KDF output, and wrapping key. Raw keys
+are never reused between the LUKS2 and object-vault layers.
+
+### 8.3 Keyslot rules
+
+A keyslot wraps only random vault or recovery key material. Adding, removing,
+or changing a passphrase is an authenticated transaction. The previous slot
+remains in the live header only until the new slot and replacement header
+backup are durably verified.
+
+A memory-hard KDF raises guessing cost but does not turn a weak passphrase into
+a high-entropy secret. The UI requires a profile-appropriate secret and states
+the offline-guessing risk.
+
+Removing a LUKS2 keyslot does not revoke an old passphrase against an attacker
+who retained an earlier header backup containing that slot and the same volume
+key. True revocation against copied old headers requires a reviewed full
+volume-key and vault-key rotation, reencrypted data, retirement of old object
+keys, and controlled destruction of obsolete headers and media.
+
+Unlock secrets are accepted only through the trusted local UI or a narrowly
+specified hardware-token protocol. They never appear in command arguments,
+environment variables, files in the export bundle, logs, clipboard, or shell
+input history.
+
+Failed unlock attempts have bounded memory and CPU cost. The local UI may
+apply a coarse delay, but denial-of-service resistance cannot depend on an
+attacker-writable on-disk failure counter.
+
+### 8.4 Object envelope
+
+Every encrypted logical object has a canonical profile-fixed header containing
+at least:
+
+```text
+[
+ vault_format_version,
+ vault_profile_id,
+ network_id,
+ composer_instance_id,
+ object_type,
+ object_id,
+ object_generation,
+ transaction_generation,
+ key_epoch,
+ plaintext_length,
+ padded_length,
+ nonce,
+ ciphertext
+]
+```
+
+All fields preceding `ciphertext` are authenticated associated data. The
+profile fixes lengths, encoding, nonce construction, padding classes, AEAD,
+KDF, maximum plaintext, and key epoch. Unknown fields, alternate encodings,
+nonce reuse, invalid padding, counter wrap, or authentication failure reject
+the object.
+
+`composer_instance_id` is a random local domain separator. It is never placed
+in relay-facing bundles, contact cards, messages, PKI, storage records, public
+logs, or release metadata.
+
+### 8.5 Object classes
+
+The vault separates at least these object classes and key purposes:
+
+| Class | Examples | Restore rule |
+| --- | --- | --- |
+| Identity | contact roots, handshake identities | only through identity recovery policy |
+| Contact | public roots, fingerprints, local labels, verification decisions | public and local metadata may be recovered |
+| Messaging live state | ratchets, prekeys, skipped keys, ACK and dedup windows | stale copy never resumes |
+| Storage live state | capabilities, indexes, tombstones, receipts, retry generations | stale copy never resumes |
+| Content | drafts, inbox, sent plaintext, reassembly | optional local retention, not required for identity recovery |
+| Protocol outbox | immutable envelopes, boxes, packets, reply material | exact live instance only |
+| PKI state | genesis root, highest consensus, log checkpoint, manifests | monotonic verification required |
+| Release state | trusted roots, metadata versions, installed target, rollback floor | monotonic verification required |
+| Local control | transaction journal, state commitment, anchor receipt | never exported or identity-recovered as live state |
+
+### 8.6 Candidate primitives
+
+`FOG-COMPOSER-CANDIDATE-LINUX-VAULT-1` evaluates Argon2id for unlock key
+derivation and XChaCha20-Poly1305 for object protection through maintained
+reviewed libraries. The candidate uses random nonces from the OS CSPRNG and
+purpose-separated KDF outputs.
+
+No primitive, parameter, library, ABI, database, or vault profile becomes
+active merely because it appears here. Activation requires exact versions,
+byte-level vectors, nonce analysis, crash tests, benchmarks, dependency
+review, and independent security review.
+
+## 9. Transactional State Model
+
+### 9.1 One transaction owner
+
+Exactly one `fog-compose` process opens the mutable vault for writing. It uses
+one transaction engine capable of atomic durable commit across every logical
+object participating in a protocol transition.
+
+Messaging ratchet state, storage capability state, outbox objects, PKI
+monotonic state, application queue state, import deduplication, and export
+eligibility MUST NOT be committed through independent databases or eventually
+consistent workers.
+
+### 9.2 State commitment
+
+Every security-critical transaction produces a canonical `StateCommitment`:
+
+```text
+[
+ commitment_format_version,
+ vault_profile_id,
+ network_id,
+ composer_instance_id,
+ transaction_generation,
+ previous_commitment,
+ encrypted_catalog_root,
+ highest_consensus_epoch,
+ consensus_hash,
+ transparency_tree_size,
+ transparency_root_hash,
+ release_root_version,
+ installed_release_version,
+ import_generation,
+ export_generation,
+ transaction_class
+]
+```
+
+The commitment uses a profile-fixed authenticated hash or MAC construction.
+It contains no plaintext, contact identifier, message identifier, capability,
+box ID, or application type. It remains local except for a private external
+anchor that is explicitly part of the same Composer trust domain.
+
+### 9.3 Unanchored commit
+
+An unanchored profile:
+
+1. stages all new encrypted objects and the next catalog separately;
+2. validates cross-object invariants and resource bounds;
+3. writes and syncs the transaction journal;
+4. atomically selects the new catalog and state commitment;
+5. syncs the database and containing filesystem metadata;
+6. only then releases export eligibility or authenticated plaintext.
+
+This detects ordinary partial writes and local history discontinuity. A
+complete older vault copy containing its matching keys and journal can still
+pass.
+
+### 9.4 Externally anchored commit
+
+An anchored profile uses a prepared generation so the external effect never
+precedes the anchor:
+
+1. retain generation `N` as the active catalog;
+2. stage generation `N+1`, its encrypted objects, undo information, and exact
+ commitment in a durable `PREPARED` namespace;
+3. sync the complete prepared namespace without exposing its work;
+4. ask the independent anchor to advance from the exact accepted generation
+ and commitment to `N+1` and the new commitment;
+5. receive and verify one anchor receipt bound to the instance, generations,
+ old commitment, and new commitment;
+6. atomically select `N+1` as active and persist the receipt;
+7. sync the active selector and journal;
+8. only then export work or render newly accepted plaintext.
+
+The anchor operation is compare-and-advance, not an unchecked write. It must
+reject a wrong old generation, wrong old commitment, repeated alternate next
+commitment, counter wrap, unauthorized reset, or another instance.
+An exact retry of an already completed compare-and-advance is idempotent and
+returns the same authenticated successor state without another increment.
+
+### 9.5 Crash reconciliation
+
+At startup:
+
+- anchor equals latest finalized local commitment: open normally;
+- anchor equals the one exact durable prepared successor: finalize it before
+ any other operation;
+- anchor remains at the finalized predecessor and no external effect was
+ released: discard the prepared successor using its durable staging state;
+- anchor is ahead without the exact prepared successor: enter
+ `RECOVERY_REQUIRED`;
+- anchor has the same generation but another commitment: enter
+ `CLONE_OR_TAMPER_DETECTED`;
+- local state is ahead of, behind, or unrelated to the anchor outside the
+ permitted one-step reconciliation: enter `RECOVERY_REQUIRED`.
+
+No user confirmation, clock change, file rename, or import bundle overrides a
+mismatch.
+
+### 9.6 Anchor assurance levels
+
+The registry defines:
+
+- `LOCAL_CHAIN`: no external anchor and no complete-rollback claim;
+- `HOST_BOUND_ANCHOR`: useful against accidental snapshot restore but not a
+ hostile MicroVM host controlling the anchor;
+- `INDEPENDENT_ANCHOR`: a separate hardware or physically controlled state
+ that is outside the vault and host rollback domain.
+
+A TPM 2.0 NV counter is only a candidate building block. The active anchor
+profile must prove reset authorization, endurance, atomic crash behavior,
+binding between generation and commitment, device replacement, backup,
+recovery, and denial-of-service behavior. A bare increment command is not by
+itself the FOG anchor protocol.
+
+The anchor has no network interface and receives only its private local
+instance handle, generation numbers, and opaque fixed-length commitments. It
+does not receive the commitment body, object catalog, contact, message,
+capability, application type, plaintext, or vault key. It necessarily observes
+local anchor-operation count and timing, which remains an endpoint metadata
+risk.
+
+### 9.7 Database candidate
+
+The Linux candidate evaluates one SQLite database with one writer and an exact
+durability profile. The selected journal mode, synchronization level,
+filesystem, block device, locking behavior, power-loss assumptions, and backup
+API become immutable profile inputs.
+
+Copying an SQLite main file while a transaction or hot journal exists is not a
+backup. The implementation uses the reviewed backup API or a fully quiescent
+profile-specific snapshot and preserves every required journal and metadata
+file. Database integrity checks do not replace object authentication or an
+external monotonic anchor.
+
+## 10. Composer Transfer Bundle
+
+### 10.1 Fixed outer header
+
+Every Composer bundle starts with this exact 128-byte header:
+
+```text
+offset length field
+0 8 magic
+8 2 bundle_format_version
+10 1 bundle_kind
+11 1 flags
+12 4 bundle_profile_id
+16 32 network_id
+48 32 bundle_nonce
+80 8 payload_length
+88 4 record_count
+92 4 record_table_length
+96 32 payload_digest
+```
+
+`magic`, version, kind, flags, profile, counts, and lengths have one canonical
+encoding. `bundle_nonce` contains 256 CSPRNG bits and is unique to the bundle;
+it is not an identity or protocol replay token. `payload_digest` provides
+bounded corruption detection and canonical deduplication only. It does not
+authenticate the producer.
+
+### 10.2 Fixed record header
+
+Each record starts with this exact 48-byte header:
+
+```text
+offset length field
+0 2 record_type
+2 2 record_version
+4 4 flags
+8 8 actual_length
+16 8 padded_length
+24 16 record_id
+40 8 reserved
+```
+
+The body contains `actual_length` bytes followed by zero padding to
+`padded_length`. The record table lists exact ordered offsets and types before
+any body is dispatched. `record_id` is random and bundle-local. Reserved bits,
+duplicate IDs, overlap, gaps outside canonical padding, non-zero padding,
+integer overflow, inconsistent lengths, and trailing data reject the complete
+bundle.
+
+Bundles contain no nested bundle, archive, directory, symlink, device node,
+filesystem image, filename, URI, MIME type, compression stream, or executable
+metadata.
+
+### 10.3 Bundle kinds
+
+The registry defines separate allowlists for:
+
+- `RELAY_EXPORT`: committed KEMSphinx submissions and bounded public relay
+ scheduling hints already authorized by the Composer;
+- `RELAY_IMPORT`: complete signed PKI objects, opaque KEMSphinx replies,
+ conflict evidence, and bounded public relay state;
+- `CONTACT_EXPORT` and `CONTACT_IMPORT`: one bounded contact card, voucher, or
+ authenticated contact transition;
+- `RECOVERY_EXPORT` and `RECOVERY_IMPORT`: one encrypted recovery package and
+ its public format metadata;
+- `UPDATE_IMPORT`: signed release metadata and exact target artifacts handled
+ only by the maintenance environment.
+
+Wrong-direction records reject the bundle. `UPDATE_IMPORT` is never parsed by
+the unlocked ordinary Composer process, and ordinary relay or contact bundles
+cannot contain an executable target.
+
+### 10.4 Absolute version-1 limits
+
+These are parser ceilings, not recommended operational batch sizes:
+
+| Item | Absolute limit |
+| --- | --- |
+| Outer header | exactly 128 bytes |
+| Record header | exactly 48 bytes |
+| Nesting | forbidden |
+| Relay bundle | 64 MiB |
+| Relay records | 2048 |
+| One relay record | 256 KiB |
+| Contact bundle | 1 MiB |
+| Contact records | 64 |
+| Recovery bundle | 64 MiB |
+| Recovery records | 256 |
+| Update metadata | 64 MiB |
+| Complete update bundle | 16 GiB, streamed only |
+| Update records | 4096 |
+| Unknown record type or flag | reject complete bundle |
+
+FOG-SX and deployment profiles set lower transport and memory limits. An
+update target is streamed to an inactive verified image and never allocated as
+one memory buffer.
+
+### 10.5 Authentication ownership
+
+The outer bundle is a transport container. Authentication remains owned by
+each embedded protocol:
+
+- PKI objects use authority signatures and monotonic consensus rules;
+- KEMSphinx replies use their packet, SURB, token, storage, and message
+ authentication;
+- contact objects use the exact contact-root or voucher signature rules;
+- recovery objects use the recovery envelope and separately held key;
+- updates use the release metadata threshold and target hashes.
+
+A Composer-relay pairing key MAY authenticate a local bundle envelope to
+reduce random injection and accidental cross-user delivery. The relay is
+still untrusted, a pairing MAC is never accepted as message or PKI
+authenticity, and the pairing handle is not exported into the FOG network.
+
+## 11. Import Processing
+
+### 11.1 Quarantine
+
+Raw input first enters a new size-limited quarantine object created with an
+unpredictable local name and exclusive creation. The decoder streams the
+input, enforces the outer limit, calculates the digest, syncs the completed
+object, and closes the input before `fog-compose` can open it.
+
+The decoder never extracts files or follows a path supplied by input. Partial,
+oversized, timed-out, or multiply opened inputs are deleted without entering
+the vault.
+
+### 11.2 Validation order
+
+The Composer:
+
+1. opens the quarantine object read-only without following links;
+2. validates exact total size and the 128-byte header;
+3. validates bundle direction, network, profile, kind, count, and limits;
+4. validates the complete record table and non-overlap before allocation;
+5. streams every record through its owning strict parser into staged state;
+6. verifies every inner signature, AEAD, hash, token, generation, expiry, and
+ monotonic rule required by that record type;
+7. compares conflicting complete PKI views and preserves evidence rather than
+ merging them;
+8. computes all cross-record and cross-protocol state transitions;
+9. commits import digest, deduplication, new protocol state, inbox, and any
+ resulting outbox through Section 9;
+10. only after final commit and required anchor advance, releases plaintext or
+ marks resulting work exportable;
+11. destroys staged plaintext and expires the quarantine object.
+
+One invalid critical record rejects the complete bundle. The parser does not
+continue in order to collect attacker-selected diagnostic detail.
+
+### 11.3 Duplicate and replay handling
+
+The Composer stores a keyed local import identifier derived from the complete
+bundle digest and profile. An exact duplicate is idempotent and does not repeat
+rendering, ratchet advancement, capability advancement, voucher consumption,
+update installation, or recovery.
+
+The bundle identifier is only an outer deduplication aid. Each embedded
+protocol still performs its own replay and generation checks. Repacking the
+same records into another bundle cannot bypass those checks.
+
+### 11.4 Failure privacy
+
+Detailed failure remains local and bounded. The Composer does not
+automatically export a parse error, invalid-contact error, decryption error,
+missing-message error, stale-state error, or update-verification oracle.
+
+The UI maps failures to coarse classes such as `INVALID_IMPORT`,
+`AUTHENTICATION_FAILED`, `STALE_OR_ROLLED_BACK`, `RESOURCE_LIMIT`,
+`RECOVERY_REQUIRED`, and `UNSUPPORTED_PROFILE`. Secret values and attacker
+bytes are not copied into diagnostics.
+
+## 12. Export Processing
+
+### 12.1 Export transaction
+
+For every export generation, the Composer:
+
+1. selects only committed eligible outbox objects under the active schedule;
+2. validates their protocol profile, lifetime, retry, geometry, and state;
+3. generates any fresh KEMSphinx, SURB, route, entry, rendezvous, and reply
+ material required for this network transmission;
+4. stages the exact immutable bundle, random bundle nonce, record table,
+ digest, export generation, and outbox transitions;
+5. commits all state and advances the required external anchor;
+6. creates a new export spool object with exclusive creation;
+7. writes, syncs, seals read-only, and reopens the spool object to verify its
+ exact bytes and digest;
+8. only then authorizes the export encoder to transmit that one object.
+
+A crash before step 5 creates no exportable bytes. A crash after step 5
+recovers the exact committed bundle. A crash during spool creation rebuilds
+only those same committed bytes and does not advance a ratchet, capability, or
+packet generation again.
+
+### 12.2 Duplicate physical export
+
+Copying or replaying one already sealed bundle can cause duplicate relay
+submission. Bundle, packet, courier, storage, and message deduplication remain
+required. The Composer never assumes physical transfer occurred merely
+because it authorized the encoder.
+
+If the outcome is unknown, later retry creates the fresh outer packet material
+required by the owning packet and storage profiles from already committed
+inner state. It does not reconstruct an end-to-end message envelope or reuse a
+single-use reply secret contrary to those profiles.
+
+### 12.3 Export contents
+
+Relay-facing export MUST NOT contain:
+
+- plaintext, local UI strings, application names, contact labels, drafts, or
+ message history;
+- long-term user signatures over the bundle, stable Composer instance IDs, or
+ vault generations;
+- message, session, capability, box, or receipt identifiers outside their
+ required opaque cryptographic layer;
+- private PKI, release, recovery, backup, state, or transfer keys;
+- filesystem paths, usernames, hostnames, locale, timezone, device model, or
+ software diagnostics.
+
+Export size class and timing remain observable to the physical transfer path
+and blind relay. Cover and scheduling profiles, not the bundle container
+alone, govern those metadata claims.
+
+### 12.4 Spool retention
+
+An opaque export spool item remains until one of:
+
+- an explicitly lower-assurance local transfer profile returns an
+ authenticated acceptance permitted by that profile;
+- a bounded re-export window ends;
+- the owning protocol produces authenticated terminal evidence;
+- the operation is explicitly cancelled before a forbidden state transition;
+- recovery freezes the entire instance.
+
+The high-assurance simplex profile has no automatic receiver acceptance path.
+Its Composer therefore relies on bounded spool retention and later owning-
+protocol evidence, not an FOG-SX acknowledgment.
+
+Deletion of a spool item never rewinds its protocol state. Sensitive reply
+material and ephemeral packet keys follow their shorter owning lifetimes.
+
+## 13. Backup and Recovery
+
+### 13.1 Recovery goals
+
+Composer recovery is designed to preserve the minimum long-term authority
+needed to reestablish an identity and verify known contacts. It is not a
+transparent snapshot restore and does not promise recovery of undelivered
+messages, forward-secret message keys, live storage positions, consumed
+prekeys, pending acknowledgments, or current network work.
+
+The default `IdentityRecoveryPackage` MAY contain:
+
+- the FOG network ID and genesis trust-anchor material;
+- the long-term pairwise or accountless identity roots explicitly selected
+ for recovery;
+- contact public roots, verified fingerprints, and verification status;
+- encrypted local contact labels when the user includes them;
+- release trust roots and minimum accepted release version;
+- the latest public PKI checkpoint and consistency metadata as a recovery
+ starting point, never as permission to roll backward;
+- identity-generation and recovery-package sequence metadata;
+- a declaration that every messaging session and storage stream must be
+ replaced before use.
+
+The default package MUST NOT contain live ratchets, chain keys, message keys,
+skipped keys, one-time prekeys, active storage read or write capabilities,
+outbox ciphertexts, SURBs, reply tokens, pending packets, deduplication
+windows, transfer-pairing keys, local anchor credentials, or an active
+Composer instance ID.
+
+### 13.2 Recovery envelope
+
+The recovery plaintext is one canonical bounded object with an explicit
+format version, network, identity set, package sequence, creation release,
+key profile, content allowlist, and restore policy. It is padded and
+authenticated under a random recovery data key.
+
+That random key is wrapped by a distinct recovery key hierarchy. Recovery key
+material is stored separately from the recovery ciphertext. A recovery
+passphrase, if supported, uses its own profile-fixed memory-hard KDF, salt, and
+parameters and does not reuse the live-vault keyslot or passphrase verifier.
+
+Recovery filenames, QR labels, media labels, and transport checksums are not
+authenticated metadata. Every field that affects identity, version, content,
+or restore behavior is inside the authenticated envelope.
+
+### 13.3 Recovery export
+
+Recovery creation requires explicit local user confirmation and a dedicated
+ceremony outside normal message export. The Composer:
+
+1. validates that the selected identities and contact metadata are eligible;
+2. generates a fresh recovery package ID and random data key;
+3. constructs and encrypts the exact canonical package;
+4. atomically records the package sequence and digest in live state;
+5. advances the external anchor when required by the active profile;
+6. exports ciphertext and recovery key material through distinct controlled
+ paths;
+7. verifies one complete test decryption before reporting success;
+8. erases transient recovery plaintext and wrapping material.
+
+Normal relay export, contact exchange, and FOG-SX network work MUST NOT carry a
+recovery package or recovery key.
+
+### 13.4 Restore
+
+Restore occurs into a fresh verified Composer image and a newly initialized
+vault with a new random `composer_instance_id`, vault key, object key epochs,
+transfer-pairing keys, and local anchor state.
+
+After verifying and decrypting the package, the new Composer:
+
+- imports the allowed identity roots and contact verification history;
+- refuses any recovered PKI, release, or rollback state lower than the trusted
+ state embedded in the verified recovery image or independent anchor;
+- marks every historical messaging session and storage stream
+ `RECOVERY_REQUIRED` or `CLOSED`;
+- creates no message, packet, prekey, voucher, read, write, or ACK from restored
+ mutable protocol bytes;
+- obtains a current PKI view through the full long-offline consistency path;
+- verifies the current release chain and rollback floor;
+- uses the recovered identity authority to authenticate fresh contact-session
+ and storage-stream transitions;
+- warns that contacts may need independent fingerprint confirmation when
+ compromise, identity change, or ambiguous recovery is suspected.
+
+The old instance is not automatically revoked merely because a new vault was
+created. If the old device may still operate, identity compromise and clone
+procedures apply and contacts require an authenticated identity transition.
+
+### 13.5 Full-state archives
+
+A routine full copy of a live Composer vault is forbidden as a resumable
+backup. A profile MAY create a separately encrypted forensic archive for
+disaster analysis, but it is marked `NON_RESUMABLE`, contains no unlock or
+anchor key beside its ciphertext, and cannot be opened as an active vault.
+
+Copying a VM private volume, SQLite file, LUKS device, portable state
+partition, or suspended memory image is not recovery. Such a copy is clone
+evidence and freezes all live state if discovered.
+
+### 13.6 Deletion limits
+
+Deleting an object key or recovery key can make surviving ciphertext
+inaccessible under the stated assumptions. It does not prove removal from
+RAM, flash translation layers, snapshots, filesystem journals, controller
+caches, old media, recipient devices, or adversarial copies.
+
+The UI describes deletion as local best effort with explicit retained-copy
+limits. It never reports cryptographic erasure as physical proof.
+
+## 14. Offline Update Verification
+
+### 14.1 Separation of authority
+
+Release authority is separate from user identity, FOG-PKI authority, node,
+relay, storage, backup, recovery, and Composer state authority. Runtime images
+contain only public release roots and current trusted metadata, never a
+release signing key.
+
+An update distributor, relay, mirror, removable medium, QR label, or package
+manager is an untrusted transport. It cannot authorize code.
+
+### 14.2 Update candidate
+
+`FOG-COMPOSER-CANDIDATE-UPDATE-TUF-1` evaluates an exact future TUF revision
+and maintained client implementation. The candidate uses distinct threshold
+roles for root, targets, snapshot, and timestamp metadata, consistent target
+hashes and lengths, version monotonicity, expiry, and sequential root
+rotation.
+
+The selected release profile MUST pin:
+
+- exact TUF specification and implementation revisions;
+- root, targets, snapshot, timestamp, and delegated-role thresholds;
+- key algorithms, key IDs, role separation, and offline-key requirements;
+- canonical metadata encoding and absolute size limits;
+- trusted-time and maximum-clock-uncertainty behavior;
+- target naming, architecture, deployment profile, and compatibility fields;
+- installed-version, minimum-version, revocation, and rollback-floor rules;
+- root rotation, repository recovery, and emergency response ceremonies.
+
+TUF metadata transport security is not release authenticity. A valid older
+but unexpired view is still subject to the Composer's highest accepted
+versions, rollback floor, and freeze policy.
+
+### 14.3 Update bundle validation
+
+The maintenance environment:
+
+1. verifies the fixed Composer `UPDATE_IMPORT` framing and streaming limits;
+2. starts from the currently trusted release root stored in monotonic state;
+3. applies every intermediate root version sequentially with the required old
+ and new thresholds;
+4. verifies timestamp, snapshot, targets, delegations, versions, expiry,
+ hashes, lengths, and consistent-snapshot rules;
+5. rejects metadata below any locally trusted version or rollback floor;
+6. verifies target architecture, deployment profile, state-schema range,
+ boot profile, and hardware requirements;
+7. streams each target to inactive storage while hashing and enforcing its
+ exact declared length;
+8. verifies the complete inactive image and its signed boot and root digest;
+9. records a signed-metadata-bound prepared boot transition without opening
+ the Composer vault;
+10. activates the new boot slot for one bounded trial;
+11. lets only the verified target image, after explicit user unlock, validate
+ the prepared transition, migrate state if required, commit the installed
+ release and rollback floor through Section 9, and mark boot success.
+
+No target is executed, mounted writable, or parsed by its own code before its
+owning metadata, hash, and length have been verified.
+
+### 14.4 Trusted time and freeze
+
+Update expiry requires a trusted update-start time with a stated uncertainty.
+File modification times, removable-media clocks, relay timestamps, target
+timestamps, HTTP headers, and unauthenticated user input are not trusted time.
+
+If time uncertainty prevents expiry validation, the Composer stops update
+installation and invokes a separately authenticated time-recovery ceremony.
+It does not disable expiry. Highest accepted metadata versions reduce rollback
+risk but do not independently prove that a distributor has supplied the
+latest release.
+
+### 14.5 A/B image and boot failure
+
+The Portable candidate uses inactive-image installation and a bounded boot
+trial. Automatic fallback is permitted only to an image still above the
+authenticated rollback floor and not explicitly revoked.
+
+If the new image and the prior image are both unauthorized or incompatible,
+the system enters signed recovery media rather than booting an older vulnerable
+release. A boot-success marker is not trusted if it can be rolled back without
+the profile's monotonic control.
+
+### 14.6 State migration
+
+A release declares the exact source and target vault schema range. Migration:
+
+- runs in a dedicated mode of the verified target image after explicit user
+ unlock; the maintenance update verifier never receives vault keys;
+- runs offline with network and ordinary import/export disabled;
+- opens the old state through the old reviewed reader and writes a separately
+ staged new catalog;
+- authenticates and validates every source object before transformation;
+- rejects unknown-critical object types and counter or size overflow;
+- preserves no old live-state copy as a resumable second Composer;
+- commits the new schema and release version through Section 9;
+- cannot be reversed after external effect or anchored finalization.
+
+If migration fails before finalization, the old still-authorized image and
+state remain active. If the anchor or state has advanced but reconciliation
+cannot prove the exact prepared migration, recovery is required.
+
+### 14.7 Emergency response
+
+Emergency metadata may revoke a target or raise the minimum release version,
+but uses the normal authenticated root and delegated authority rules. There is
+no unsigned rescue build, universal operator password, hidden update URL,
+network bypass, or local force-install flag.
+
+## 15. PKI, Time, and Monotonic Consumer State
+
+### 15.1 PKI import
+
+The Composer persists the complete trusted PKI consumer state required by
+`FOG-PKI` in the same security-critical transaction as any route, profile,
+message, or storage work that first depends on it.
+
+It accepts a newer view only after validating:
+
+- network and trust-anchor identity;
+- canonical full consensus and independent authority quorum;
+- sequential authority-set transitions;
+- epoch, validity, freshness, and clock uncertainty;
+- archive inclusion and append-only consistency from the stored checkpoint;
+- active packet, wire, messaging, storage, entry, cover, and Composer profiles;
+- complete current storage manifests and key windows;
+- split-view, equivocation, and conflict evidence.
+
+A bundle containing multiple valid conflicting views freezes affected work and
+preserves evidence. It does not select the numerically highest view or merge
+descriptors.
+
+### 15.2 Offline time
+
+The Composer maintains separate notions of:
+
+- monotonic process time for one boot session;
+- authenticated protocol epoch and version progression;
+- profile-approved civil time with explicit uncertainty;
+- release-metadata update-start time.
+
+An RTC can be a candidate input but is not trusted merely because it is
+battery-backed. Clock rollback, implausible jump, uncertainty overflow, or
+disagreement with authenticated epoch bounds stops new time-sensitive work.
+
+The UI permits a user to report the clock problem, not to declare an arbitrary
+time valid. Exact offline time recovery remains a profile activation gate.
+
+## 16. Native Applications and Safe Rendering
+
+### 16.1 Common application boundary
+
+`fog-drop`, `fog-mailbox`, and `fog-im` are modules inside the Composer trust
+domain. They receive authenticated bounded application frames only after
+messaging, storage, import, and state commit. They do not parse raw transfer,
+KEMSphinx, storage, or ratchet bytes.
+
+Applications cannot select packet geometry, route length, storage replica
+count, retry timing, cover class, cryptographic primitive, update channel, or
+external renderer.
+
+### 16.2 Initial content profile
+
+The initial content profile supports bounded UTF-8 plain text with canonical
+normalization rules and a small fixed set of non-active local presentation
+attributes. It rejects invalid UTF-8, control-character abuse, bidirectional
+text policy violations, oversized grapheme sequences, unknown critical
+fields, and active content.
+
+No content triggers:
+
+- network or filesystem access;
+- contact creation or verification change;
+- command execution, URL opening, media decoding, font installation, or
+ external process launch;
+- automatic reply, read receipt, typing indicator, preview, or notification
+ containing plaintext outside the unlocked Composer;
+- import, update, recovery, profile, or key transition.
+
+### 16.3 Local UI status
+
+The UI distinguishes at least:
+
+- locally queued but not exported;
+- exported with unknown relay outcome;
+- courier accepted, replica quorum committed, and degraded storage;
+- authenticated recipient Composer commit acknowledgment;
+- expired or uncertain delivery;
+- contact fingerprint verified, unverified, changed, or recovery pending;
+- PKI fresh, stale but valid, expired, split, or recovery required;
+- vault locally consistent, externally anchored, unanchored, or mismatched;
+- installed release verified, update available, revoked, or time-blocked.
+
+It never labels courier acceptance as delivery, replica commit as human read,
+encryption as anonymity, networklessness as host integrity, or local hash-chain
+verification as complete anti-rollback.
+
+### 16.4 Plaintext lifetime
+
+Plaintext is decrypted only for the active operation or visible bounded view.
+Search indexes, caches, undo history, previews, clipboard, recent-file lists,
+accessibility bridges, screenshots, and notifications are disabled unless a
+later profile explicitly bounds and protects them.
+
+Lock, suspend, inactivity timeout, display detachment, update mode, integrity
+failure, anchor failure, or fatal parser fault closes views and erases active
+keys and staging memory on a best-effort basis.
+
+## 17. State and Key Lifecycle
+
+| Material | Owner | Persistence | Transition or destruction |
+| --- | --- | --- | --- |
+| Human unlock secret | user | never stored as plaintext | replace through authenticated keyslot rewrap |
+| Unlock KDF output or KEK | Composer unlock transaction | memory only | erase after vault key unwrap or lock |
+| Random vault key | one Composer instance | wrapped keyslot plus unlocked memory | rotate by profile; never export or identity-recover |
+| Object key epoch | Composer vault | wrapped or derived encrypted state | rotate by object class; retain only for live objects |
+| Local state-authentication key | Composer vault | one instance | erase on instance retirement; never use for backup |
+| Composer instance ID | Composer vault | lifetime of one active instance | replace on restore or reinitialization; never export |
+| State commitment chain | Composer vault | permanent for one instance | preserve until explicit retirement |
+| External anchor key or handle | independent anchor domain | profile-specific monotonic lifetime | controlled replacement requires recovery ceremony |
+| Import quarantine bytes | sandbox and Composer | one bounded import | delete after commit or rejection |
+| Import dedup identifier | Composer vault | maximum bundle replay window | expire by authenticated profile, not input time |
+| Export spool ciphertext | export encoder and Composer | bounded transfer or retry window | delete without rewinding protocol state |
+| Transfer-pairing key | Composer and local blind relay boundary | local pairing generation | rotate on pairing compromise; never authenticate messages |
+| Recovery data key | recovery transaction | package creation or restore only | erase after verified wrap or unwrap |
+| Recovery wrapping key | user recovery domain | separate from package ciphertext | rotate by creating and testing a new package |
+| Identity root in recovery | encrypted recovery package | explicit identity lifetime | revoke or replace through identity protocol after compromise |
+| Live ratchet and capability state | current Composer instance only | encrypted mutable state | freeze on restore, clone, rollback, or compromise |
+| Release trust roots | Composer maintenance state | sequential root lifetime | rotate only through authenticated old and new thresholds |
+| Installed-release floor | Composer and external anchor where claimed | monotonic installation lifetime | only increase through authenticated metadata |
+| Temporary plaintext and message keys | Composer process | one transaction or view | best-effort erase immediately after owning commit or close |
+
+Purpose-separated keys MUST NOT be converted, copied, or relabeled to satisfy a
+different row.
+
+## 18. Failure and Recovery States
+
+### 18.1 Minimum vault states
+
+The Composer state machine includes:
+
+- `UNINITIALIZED`: no identity or mutable vault exists;
+- `LOCKED`: image verified, vault keys absent from active memory;
+- `UNLOCKING`: bounded keyslot and state verification in progress;
+- `READY_UNANCHORED`: locally consistent, no complete-rollback claim;
+- `READY_ANCHORED`: local and independent anchor state match;
+- `IMPORT_STAGED`: one bounded import is parsed but has no effect;
+- `EXPORT_PREPARED`: exact export state is durable but not yet released;
+- `UPDATE_STAGED`: inactive release verified but not activated;
+- `RECOVERY_REQUIRED`: ordinary protocol actions forbidden;
+- `CLONE_OR_TAMPER_DETECTED`: local and anchor history conflict;
+- `LOCKDOWN`: integrity, runtime, or secret-lifetime policy failed;
+- `RETIRED`: no further use of instance keys or live protocol state.
+
+### 18.2 Failure table
+
+| Condition | Required response |
+| --- | --- |
+| Boot signature or root-image verification failure | stop before vault unlock |
+| Vault keyslot authentication failure | generic local failure, no object parsing |
+| Object AEAD or canonical encoding failure | quarantine object or vault, no partial use |
+| Database integrity or durability uncertainty | lock and enter authenticated recovery |
+| Local commitment-chain break | freeze all mutable protocol state |
+| External anchor mismatch | `RECOVERY_REQUIRED` or `CLONE_OR_TAMPER_DETECTED` |
+| Missing anchor in an anchor-required profile | no export, render, or state advancement |
+| Malformed or oversized import | reject complete bundle and delete quarantine |
+| One invalid critical bundle record | reject complete bundle |
+| Duplicate valid import | idempotent success without repeated effect |
+| Export spool partial write | rebuild exact committed bytes or discard partial file |
+| PKI split or consistency failure | freeze new network work and preserve evidence |
+| Clock uncertainty outside profile | stop time-sensitive PKI and update acceptance |
+| Update signature, expiry, hash, length, or version failure | retain verified non-revoked version or stop |
+| Migration failure before finalization | keep old still-authorized state and image |
+| Migration or anchor ambiguity after advance | recovery required, no downgrade |
+| Recovery package failure | no identity import and no detailed oracle |
+| Lock, suspend, display loss, or runtime policy failure | erase active keys best effort and stop |
+
+User-visible diagnostics remain local, coarse, and free of attacker-controlled
+secret bytes. A failure never opens networking, mounts an internal disk,
+enables a general shell, skips verification, accepts an older profile, or
+exports an automatic error.
+
+## 19. Resource Limits and Abuse Resistance
+
+Every active Composer profile defines lower limits within the absolute bundle
+ceilings for:
+
+- vault objects, object bytes, transaction objects, and staged generations;
+- identities, contacts, sessions, prekeys, skipped keys, capabilities, and
+ storage streams;
+- drafts, messages, fragments, reassembly groups, history, and attachments;
+- protocol outbox, inbox, deduplication, ACK, receipt, retry, and tombstone
+ state;
+- quarantine items, bundle bytes, record count, parser depth, and parse time;
+- export spool items, bytes, re-export attempts, and retention;
+- PKI objects, consensus views, proof nodes, manifests, conflicts, and history;
+- update metadata, targets, stream bytes, staging space, and migration work;
+- recovery identities, contacts, labels, package bytes, and attempts;
+- Argon2 memory, CPU, lanes, attempts, and concurrent KDF calls;
+- UI text bytes, graphemes, lines, rendering time, and notification queue;
+- anchor operations, prepared generations, reconciliation attempts, and
+ device timeouts;
+- memory, file descriptors, processes, threads, temporary files, and disk
+ reserve.
+
+Limits are enforced before allocation or expensive cryptography where the
+owning format permits. Authenticated contacts remain untrusted for resource
+purposes. A valid signature or ciphertext does not authorize unbounded local
+storage, rendering, KDF work, or notifications.
+
+Disk-full handling preserves the latest finalized catalog and anchor state.
+The Composer does not evict security-critical replay, ratchet, capability,
+commitment, or rollback state according to least-recently-used behavior. It
+stops new work or applies an authenticated retention policy.
+
+## 20. Logging and Local Observability
+
+The default release logs only coarse boot, lock, integrity, capacity, and
+failure-class counters needed to operate the local device. Logs are bounded,
+stored inside the encrypted vault or volatile memory, and deleted by a fixed
+policy.
+
+The Composer MUST NOT log or export:
+
+- plaintext, drafts, rendered content, contact labels, or fingerprints;
+- private keys, unlock material, recovery keys, capabilities, or ratchets;
+- message, session, box, receipt, packet, SURB, reply, voucher, or bundle
+ identifiers;
+- routes, replica selection, entry sets, import timing histories, or per-
+ contact activity;
+- object ciphertext samples, failed attacker input, decrypted fragments, or
+ detailed cryptographic errors;
+- filesystem paths containing user identity, hostnames, locale, timezone, or
+ device serial numbers;
+- state commitments or anchor receipts in a generic support bundle.
+
+There is no automatic telemetry, update check, crash upload, or remote
+diagnostic channel. A manually exported diagnostic report uses an explicit
+reviewed schema, contains only coarse redacted status selected by the user,
+and never includes a raw log or vault object.
+
+## 21. Candidate Implementation Profiles
+
+### 21.1 Linux vault candidate
+
+`FOG-COMPOSER-CANDIDATE-LINUX-VAULT-1` combines:
+
+- an authenticated boot artifact and read-only `dm-verity` root image;
+- a dedicated LUKS2 mutable volume with Argon2id keyslots;
+- object-level XChaCha20-Poly1305 authenticated encryption;
+- one transactional SQLite database with one writer;
+- immutable import quarantine and export spool files;
+- disabled network stack, swap, hibernation, core dumps, and active-content
+ desktop services.
+
+This combination is a review target, not a composed security proof. LUKS2,
+dm-verity, AEAD, SQLite, boot firmware, filesystem, storage hardware, and the
+Composer transaction protocol have different failure and trust assumptions.
+
+### 21.2 Qubes MicroVM candidate
+
+`FOG-COMPOSER-CANDIDATE-MICROVM-QUBES-1` evaluates:
+
+- a dedicated persistent Composer qube with no NetVM;
+- an immutable reviewed template or standalone image measurement;
+- one private encrypted state volume unlocked inside the guest;
+- exact qrexec policies for bounded import and export services only;
+- separate untrusted transfer qubes where physical device support requires
+ them;
+- explicit denial of file copy, clipboard, URL opening, general command,
+ update proxy, audio, camera, block, USB, and arbitrary qrexec services.
+
+qrexec is a host-mediated data channel and the Qubes host remains trusted for
+guest confidentiality and integrity. A host-controlled vTPM is not an
+independent anchor against that host.
+
+### 21.3 Portable Linux candidate
+
+`FOG-COMPOSER-CANDIDATE-PORTABLE-LINUX-1` reuses the Linux vault profile but
+boots a signed read-only image on dedicated offline hardware. It requires
+driver removal, internal-disk automount denial, separate RX/TX devices,
+physical inspection, and a profile-selected independent monotonic anchor for
+any complete-rollback claim.
+
+Secure Boot without a narrowly controlled FOG release root, root-image
+verification without an authenticated root digest, or a TPM without a reviewed
+state-binding protocol does not satisfy the complete candidate.
+
+### 21.4 Activation gates
+
+Before any candidate receives an active numeric profile, FOG MUST freeze and
+verify:
+
+1. exact operating system, kernel, bootloader, firmware assumptions, image
+ format, and immutable-root construction;
+2. exact LUKS2, Argon2id, AEAD, KDF, hash, database, filesystem, and library
+ revisions and parameters;
+3. byte-exact vault object, commitment, bundle, record, recovery, and update
+ serialization;
+4. nonce uniqueness, key-purpose separation, wrapping, rotation, and deletion;
+5. database atomicity, sync, power-loss, disk-full, corruption, and backup
+ behavior on supported hardware;
+6. external-anchor state binding, crash protocol, endurance, reset, clone,
+ replacement, and recovery;
+7. exact MicroVM device model and qrexec or equivalent policy;
+8. exact Portable driver set, mounts, Secure Boot ownership, dm-verity chain,
+ and physical transfer direction;
+9. exact TUF revision, client, metadata encoding, thresholds, trusted time,
+ root rotation, rollback floor, revocation, and offline repository workflow;
+10. parser fuzzing, UI rendering, import/export duplication, hostile media,
+ migration, recovery, and update fault injection;
+11. reproducible or independently verifiable builds, dependency provenance,
+ release ceremony, and rollback rehearsal;
+12. independent endpoint, cryptographic integration, and implementation
+ review before public claims.
+
+## 22. Conformance and Adversarial Tests
+
+Before the local PoC, FOG-COMPOSER requires deterministic positive and
+negative tests for:
+
+- image signature, boot argument, root digest, read-only root, and failure
+ before vault unlock;
+- absence of NICs, network drivers, network syscalls, listeners, proxies, and
+ undeclared devices;
+- MicroVM clipboard, shared directory, qrexec, device, and guest-agent denial;
+- Portable radio, internal-disk mount, foreign-filesystem, and directional
+ device denial;
+- keyslot creation, unlock, wrong secret, rewrap, rotation, and partial header
+ update;
+- object AEAD, associated data, nonce, padding, generation, key epoch, wrong
+ instance, corruption, truncation, and unknown-critical fields;
+- atomic messaging, storage, PKI, import, export, and application commits;
+- every crash point before and after prepared state, anchor advance,
+ finalization, export release, and plaintext rendering;
+- local-chain rollback, complete coherent rollback, clone, split generation,
+ anchor reset, missing anchor, same-generation conflict, and reconciliation;
+- exact 128-byte bundle and 48-byte record headers;
+- every bundle kind, record allowlist, direction, size, count, padding,
+ overlap, gap, duplicate ID, integer overflow, and trailing byte;
+- malformed QR, FOG-SX, removable-medium, contact, PKI, reply, recovery, and
+ update inputs as data only;
+- exact duplicate import and export, repacking, reordered records, replay,
+ interrupted transfer, and stale result;
+- recovery creation, separate-key handling, test decrypt, restore into a new
+ instance, and refusal to resume live state;
+- rejection of a copied VM volume, database, portable partition, or full-state
+ archive as an active restore;
+- TUF thresholds, sequential root rotation, expiry, freeze, rollback,
+ fast-forward, mix-and-match, wrong target, hash, length, platform,
+ compatibility, and revocation;
+- update stream interruption, inactive-image verification, A/B trial,
+ unauthorized fallback, migration failure, and recovery media;
+- safe text rendering, Unicode edge cases, active content, external resource,
+ notification, clipboard, and parser resource abuse;
+- disk full, fake-capacity media, I/O error, fsync failure, hot journal,
+ corrupted database, low memory, KDF exhaustion, and anchor timeout;
+- lock, inactivity, suspend, display loss, update mode, and best-effort key
+ erasure;
+- absence of prohibited data from logs, crash artifacts, swap, hibernation,
+ temporary files, export, and diagnostics.
+
+Testing MUST include parser fuzzing, property tests, transaction fault
+injection, simulated power loss, race detection, hostile peripheral fixtures,
+resource exhaustion, cross-version migrations, restore exercises, dependency
+audits, and byte-identical vectors across independent implementations.
+
+Platform evidence MUST distinguish simulator, VM, dedicated offline hardware,
+and production-profile results.
+
+## 23. Threat and Architecture Traceability
+
+| Requirement | Primary controls |
+| --- | --- |
+| `ARC-002` | no NIC, no socket service, bounded transfer only, conformance network tests |
+| `ARC-004` | local vault, messaging, KEMSphinx, storage, and Noise keys remain separate |
+| `ARC-005` | full PKI verification and monotonic consensus state before route construction |
+| `ARC-006` | common opaque bundle and packet classes across native applications |
+| `ARC-007` | explicit vault, object, transfer, backup, anchor, release, and protocol key ownership |
+| `ARC-008` | exact headers, absolute parser ceilings, object and transaction bounds |
+| `ARC-009` | fail closed on image, state, anchor, import, PKI, update, and recovery uncertainty |
+| `IF-01` | committed opaque export only, sealed spool, no stable Composer signature |
+| `IF-02` | hostile quarantine, complete parsing, owning inner authentication, atomic import |
+| `IF-12` | threshold release metadata, target verification, inactive image, rollback floor |
+| `TM-PKI-02` | persisted consensus and checkpoint monotonic state, split freeze, external anchor where claimed |
+| `TM-ENDPOINT-01` | MicroVM and Portable profiles, immutable image, encrypted vault, no network or active content |
+| `TM-ENDPOINT-02` | separate bounded binary directions, sandboxed decoder, no archive or filesystem import |
+| `TM-ENDPOINT-03` | separate recovery hierarchy, identity-only default, no stale live-state resume or file-copy multi-device |
+| `TM-APP-01` | authenticated commit before bounded plain-text rendering, no automatic actions |
+| `TM-OPS-01` | no telemetry or secret-bearing log, crash, support, or export artifacts |
+| `TM-SUPPLY-01` | separate release authority, TUF candidate, immutable verified images, provenance gates |
+| `TM-CRYPTO-01` | random data keys, memory-hard unlock, purpose-separated object keys, lifecycle table |
+| `TM-CRYPTO-02` | immutable profile registry, no runtime crypto selection or downgrade |
+| `TM-AVAIL-01` | absolute limits, staged streaming, bounded KDF and parser work, disk reserve and safe stop |
+
+## 24. Claims Deliberately Withheld
+
+FOG-COMPOSER does not yet establish:
+
+- protection of plaintext or keys from a compromised unlocked Composer;
+- protection of a MicroVM from its malicious host or hypervisor;
+- detection of a complete coherent rollback without an independent anchor;
+- safe binding or endurance of a concrete TPM, secure element, or token;
+- secure deletion from every RAM, flash, snapshot, backup, or physical copy;
+- a final operating system, database, AEAD, KDF, filesystem, or library;
+- correctness of firmware, Secure Boot implementation, peripheral, DMA, or
+ hardware randomness;
+- that network driver removal eliminates every physical or side channel;
+- that TUF alone proves the distributor supplied the latest update while the
+ Composer is isolated;
+- transparent recovery of forward-secret sessions, pending delivery, or live
+ capability streams;
+- safe multi-device state, cloud recovery, or server-held recovery secrets;
+- production security from a Qubes fixture, portable USB prototype, or local
+ fault test.
+
+## 25. Open Dependencies
+
+The structural Composer contract is fixed, but these dependencies remain open
+before an active profile or implementation:
+
+- exact supported Linux distribution, kernel, boot, immutable-image,
+ filesystem, and hardware profiles;
+- exact LUKS2, Argon2id, AEAD, KDF, database, and secure-memory selections;
+- byte-exact vault, state commitment, bundle records, recovery envelope, and
+ update metadata integration;
+- an independent monotonic-anchor construction with proven state binding,
+ crash reconciliation, endurance, replacement, and recovery;
+- a trusted offline-time and clock-uncertainty recovery ceremony;
+- exact Qubes version, qube type, template lifecycle, qrexec services, and
+ host policy for the MicroVM candidate;
+- exact Secure Boot root ownership, firmware requirements, driver manifest,
+ RX/TX devices, and media policy for Portable;
+- the full `FOG-UPDATE` repository, signing, provenance, reproducible-build,
+ revocation, and recovery contract;
+- activation of one byte-exact numeric `FOG-SX` joint profile after its fixed
+ structural frame, object, padding, parser, no-ACK, and physical-direction
+ contract passes FEC, implementation, license and IPR, resource, vector,
+ hardware, and independent review;
+- entry capsule and return-rendezvous bundles needed for complete relay
+ import/export;
+- identity compromise, revocation, contact recovery UX, and fresh-session
+ transition vectors;
+- future native attachment, full-text search, group, and multi-device
+ protocols.
+
+No implementation convenience may silently resolve these dependencies.
+
+## 26. Primary References
+
+- FOG threat model: `FOG-THREAT-MODEL.md`
+- FOG architecture: `FOG-ARCHITECTURE.md`
+- FOG public key infrastructure: `FOG-PKI.md`
+- FOG wire protocol: `FOG-WIRE.md`
+- FOG Sphinx profile framework: `FOG-SPHINX-PROFILES.md`
+- FOG messaging protocol: `FOG-MESSAGING.md`
+- FOG storage protocol: `FOG-STORAGE.md`
+- FOG simplex transfer protocol: `FOG-SX.md`
+- Qubes OS qrexec architecture:
+ <https://doc.qubes-os.org/en/r4.3/developer/services/qrexec.html>
+- Qubes OS device handling:
+ <https://doc.qubes-os.org/en/latest/user/how-to-guides/how-to-use-devices.html>
+- Linux kernel `dm-verity` documentation:
+ <https://docs.kernel.org/admin-guide/device-mapper/verity.html>
+- cryptsetup and LUKS2 specification resources:
+ <https://gitlab.com/cryptsetup/cryptsetup/-/wikis/Specification>
+- RFC 9106, Argon2 Memory-Hard Function:
+ <https://www.rfc-editor.org/rfc/rfc9106.html>
+- libsodium XChaCha20-Poly1305 documentation:
+ <https://doc.libsodium.org/secret-key_cryptography/aead/chacha20-poly1305/xchacha20-poly1305_construction>
+- SQLite atomic commit documentation:
+ <https://sqlite.org/atomiccommit.html>
+- SQLite database-corruption and backup guidance:
+ <https://sqlite.org/howtocorrupt.html>
+- Trusted Computing Group TPM 2.0 Library specification:
+ <https://trustedcomputinggroup.org/resource/tpm-library-specification/>
+- The Update Framework specification and security model:
+ <https://theupdateframework.io/spec/>
+ <https://theupdateframework.io/docs/security/>
+
+These references supply maintained formats, mechanisms, and failure lessons.
+They do not make the combined FOG endpoint secure by inheritance. FOG still
+requires exact profiles, integration analysis, hardware measurement, vectors,
+fault testing, build provenance, update and recovery rehearsal, and
+independent review.
diff --git a/docs/FOG-CRYPTO-BENCHMARKS.md b/docs/FOG-CRYPTO-BENCHMARKS.md
new file mode 100644
index 0000000..9f6ea21
--- /dev/null
+++ b/docs/FOG-CRYPTO-BENCHMARKS.md
@@ -0,0 +1,182 @@
+# FOG Cryptographic Benchmark Baseline
+
+## 1. Status
+
+This document records the first reproducible implementation benchmark for the
+non-active candidates in `FOG-CRYPTO-SUITES.md`.
+
+It is an engineering baseline, not a profile selection or activation. It does
+not establish anonymity, post-quantum security, constant-time behavior,
+production capacity, or interoperability.
+
+The executable harness and complete three-sample data are in:
+
+- `../benchmarks/crypto/`
+- `../benchmarks/crypto/results/2026-08-08-x86-64-i5-6300u.md`
+
+## 2. Snapshot
+
+The first host is an Intel Core i5-6300U with two physical cores and four
+threads, running Linux amd64, Go 1.26.5, `GOAMD64=v1`, and the `powersave`
+governor. It is useful as an older low-power x86-64 baseline, but it is not a
+substitute for the required server, ARM64, and offline Composer classes.
+
+The Go module pins:
+
+- Katzenpost `v0.0.97`;
+- HPQC `v0.0.85-0.20260715190213-e598e7ee2843`;
+- the complete transitive graph in `go.mod` and `go.sum`.
+
+The harness is isolated from future daemons. It has no network listener,
+persistent state, runtime suite registry, packet autodetection, algorithm
+fallback, or profile activation path.
+
+## 3. Coverage
+
+The measured operations are:
+
+- SHA3-256 over 4 KiB, 128 KiB, 1 MiB, and 8 MiB objects;
+- ML-DSA-65 plus Ed25519 key generation, signing, valid verification, and
+ verification with either component invalid;
+- ML-KEM-768, X25519 hashed-ElGamal, the exact HPQC split-PRF KEM, and X-Wing
+ key generation, encapsulation, and decapsulation;
+- four-logical-CPU parallel decapsulation for the two hybrid candidates;
+- exact four-hop KEMSphinx forward construction, SURB construction, each hop
+ unwrap, all-hop unwrap, reply construction, and full request/reply crypto.
+
+The harness verifies both composite signature components over the same opaque
+input before combining their results. It performs no component fallback.
+
+## 4. First-Host Medians
+
+All sequential values below use one logical CPU and the median of three
+500 ms calibrated samples. The host was not frequency-locked or isolated, so
+the raw ranges remain authoritative.
+
+### 4.1 PKI
+
+| Operation | 4 KiB | 128 KiB | 1 MiB | 8 MiB |
+| --- | ---: | ---: | ---: | ---: |
+| SHA3-256 | 19.2 us | 0.567 ms | 4.71 ms | 37.7 ms |
+| composite sign | 1.16 ms | 2.33 ms | 11.0 ms | 78.5 ms |
+| composite verify | 0.254 ms | 1.15 ms | 12.0 ms | 57.9 ms |
+
+Composite key generation measured 0.460 ms. The benchmark framing uses a
+1,984-byte public key and 3,373-byte signature. These sizes do not define the
+pending canonical FOG PKI encoding.
+
+At 128 KiB, an invalid ML-DSA-65 component measured 1.13 ms while an invalid
+Ed25519 component measured 0.715 ms. Both components were evaluated, but the
+paths were not timing-uniform. Focused statistical and implementation review
+is required before accepting a remote failure surface.
+
+### 4.2 Hybrid KEMs
+
+| Construction | key generation | encapsulation | decapsulation |
+| --- | ---: | ---: | ---: |
+| HPQC ML-KEM-768 plus X25519 split-PRF | 0.348 ms | 0.515 ms | 0.460 ms |
+| X-Wing | 0.180 ms | 0.275 ms | 0.365 ms |
+
+Both constructions use a 1,216-byte public key and 1,120-byte ciphertext in
+this dependency snapshot. The split-PRF private serialization is 1,280 bytes;
+X-Wing is 1,248 bytes.
+
+X-Wing is faster in this local snapshot. That result supports continued
+FOG-WIRE evaluation only. It does not satisfy the distinct KEMSphinx combiner
+proof obligation and cannot silently replace the retained split-PRF candidate.
+
+### 4.3 Complete KEMSphinx Geometry
+
+| Operation | Median | B/op | allocs/op |
+| --- | ---: | ---: | ---: |
+| build forward packet | 2.43 ms | 177,492 | 391 |
+| create SURB | 2.33 ms | 123,668 | 348 |
+| unwrap one hop | 0.515 to 0.519 ms | about 32,560 | 80 to 81 |
+| unwrap all four hops | 2.04 ms | 130,192 | 323 |
+| build reply from existing SURB | 11.6 us | 28,368 | 14 |
+| full request/reply crypto | 8.89 ms | 653,450 | 1,452 |
+
+The complete operation covers two 16,150-byte packets, eight total unwraps,
+one 6,058-byte SURB, and one 320-byte private reply-key block. It excludes
+persistent replay insertion, wire I/O, queues, mixing delay, storage, and cover
+traffic.
+
+The timing is acceptable for continued simulation and implementation
+profiling on an old mobile CPU. The allocation volume is not yet acceptable as
+capacity evidence and must be included in bounded-load and denial-of-service
+work.
+
+## 5. Exact-Length Integration Finding
+
+The evaluated Katzenpost API is intentionally parameterized. Direct
+`Unwrap` use did not impose FOG's exact external packet length and accepted a
+packet shortened by one byte.
+
+FOG therefore needs an explicit protocol boundary before the cryptographic
+library. The benchmark module implements a narrow adapter that requires:
+
+- exactly four path hops;
+- exactly 10,156 forward or reply payload bytes;
+- exactly 16,150 packet bytes;
+- exactly 6,058 SURB bytes;
+- exactly 10,188 encrypted reply bytes, including the payload tag;
+- exactly 320 private reply-key bytes.
+
+Both shorter and longer inputs fail before cryptographic processing. The
+adapter does not add a primitive or alternate wire format. Equivalent strict
+checks are mandatory in any future FOG implementation and conformance corpus.
+
+## 6. Deliberate Exclusions
+
+No Noise benchmark is published because FOG has not selected exact reviewed
+entry and mutual post-quantum handshake patterns. A primitive X-Wing result is
+not a Noise handshake result.
+
+No PQXDH, Triple Ratchet, or ML-KEM Braid result is published because the
+complete FOG message integration and supported implementation path remain
+unselected. Rust was also absent on the first host.
+
+The first harness also does not supply:
+
+- peak live memory or stack-use evidence;
+- persistent replay-database cost;
+- p50, p95, or p99 latency under bounded adversarial load;
+- malformed-input timing distributions or dudect-style testing;
+- fuzzing, sanitizer, or cross-implementation vectors;
+- current server, ARM64, or offline Composer measurements;
+- queue, bandwidth, cover-traffic, or long-term disclosure results;
+- a complete vulnerability, license, AEZ, or side-channel review.
+
+Direct HPQC and Katzenpost dependencies are AGPL. Their use here is evaluation
+only and does not decide the future FOG distribution license.
+
+## 7. Selection Consequences
+
+This baseline makes the following limited decisions possible:
+
+1. Retain SHA3-256 and ML-DSA-65 plus Ed25519 for continued PKI encoding,
+ vector, separability, timing, and implementation work.
+2. Retain the exact HPQC ML-KEM-768 plus X25519 split-PRF construction for the
+ calculated KEMSphinx geometry.
+3. Retain X-Wing as the leading KEM to evaluate inside a future exact reviewed
+ FOG-WIRE Noise construction.
+4. Require an exact-length FOG boundary around the maintained KEMSphinx API.
+5. Move next to the privacy and capacity simulator while leaving every
+ cryptographic candidate non-active.
+
+No numeric suite or packet profile ID is assigned.
+
+## 8. Required Next Evidence
+
+Before activation, repeat and extend the matrix on:
+
+- a current x86-64 server;
+- a lowest-supported ARM64 node or Composer;
+- the intended offline Composer hardware;
+- a controlled host with fixed governor, CPU isolation, and recorded thermal
+ behavior.
+
+Then add exact Noise handshakes, complete messaging operations, persistent
+replay work, tail latency, memory profiles, fuzzing, deterministic positive and
+negative vectors, dependency and license review, side-channel review, and an
+independent implementation or integration.
diff --git a/docs/FOG-CRYPTO-SUITES.md b/docs/FOG-CRYPTO-SUITES.md
new file mode 100644
index 0000000..48402c1
--- /dev/null
+++ b/docs/FOG-CRYPTO-SUITES.md
@@ -0,0 +1,833 @@
+# FOG Cryptographic Suite Evaluation
+
+Status: Evaluation Draft 0.1
+Date: 2026-08-08
+
+## 1. Purpose
+
+This document evaluates concrete cryptographic constructions for the distinct
+security roles in FOG. It narrows the pre-implementation candidates without
+activating a numeric protocol profile or treating algorithm names as security
+evidence.
+
+The outcome is deliberately not one global cryptographic suite. FOG needs
+different constructions for:
+
+1. PKI object hashing and authentication;
+2. KEMSphinx packet construction;
+3. adjacent-link Noise handshakes;
+4. Composer-to-Composer end-to-end messaging.
+
+Each role has a different transcript, failure boundary, lifetime, packet-size
+cost, implementation surface, and security requirement. A construction
+appropriate for one role is not automatically appropriate for another.
+
+This evaluation is subordinate to `FOG-THREAT-MODEL.md` and the structural
+protocol specifications. It does not change packet geometry, wire records,
+messaging state machines, or PKI quorum rules except for the explicit PKI
+signature-suite binding correction in Section 7.4.
+
+## 2. Status and Non-Goals
+
+This document:
+
+- records the standards and implementation evidence inspected on 2026-08-08;
+- advances named, non-active candidates where the evidence is sufficient;
+- records where an exact construction or implementation is still missing;
+- defines common activation, benchmarking, dependency, and claim gates;
+- prevents one candidate from being reused silently across security roles.
+
+This document does not:
+
+- assign a numeric hash, signature, KEM, wire, packet, or messaging profile;
+- invent a KEM, KEM combiner, signature combiner, Noise pattern, ratchet, KDF,
+ AEAD, stream cipher, or wide-block construction;
+- claim production post-quantum security, forward secrecy, post-compromise
+ security, deniability, anonymity, or side-channel resistance;
+- make an Internet-Draft equivalent to a final standard;
+- approve a library merely because it implements a standardized primitive;
+- make a construction secure by inheritance from another protocol.
+
+Numeric activation remains a separate reviewed decision after the gates in
+this document and the owning protocol specification pass.
+
+## 3. Evaluation Invariants
+
+### CRYPTO-INV-01: Purpose-specific suite families
+
+PKI, KEMSphinx, Noise, and messaging use separate suite records, identifiers,
+keys, APIs, test vectors, and transition state. There is no universal runtime
+crypto registry exposed to untrusted input.
+
+### CRYPTO-INV-02: Exact profile before attacker input
+
+The already authenticated consensus, connection context, packet geometry, or
+local messaging state selects one exact suite before parsing or cryptographic
+work. An implementation never trial-verifies alternate suites.
+
+### CRYPTO-INV-03: No component fallback
+
+A hybrid or composite construction succeeds only when its exact definition
+succeeds. It never falls back to a surviving classical or post-quantum
+component after a component, encoding, randomness, or verification failure.
+
+### CRYPTO-INV-04: Exact encoding and domain separation
+
+Every combiner input has a fixed, unambiguous encoding and an exact domain
+string. Raw concatenation of variable-length values is forbidden. Algorithm,
+profile, role, transcript, and public context fields required by the reviewed
+construction are included exactly once in the defined order.
+
+### CRYPTO-INV-05: Independent keys
+
+Component keys are generated independently. Keys are additionally separated
+by protocol, role, direction where applicable, owner, profile, and epoch or
+session. A key component is not copied from another suite record.
+
+### CRYPTO-INV-06: Uniform remote failure
+
+Malformed lengths are rejected before expensive work. Component failures,
+decapsulation failures, authentication failures, and padding failures collapse
+to the owning protocol's coarse remote behavior. Diagnostics do not reveal
+which component failed.
+
+### CRYPTO-INV-07: Evidence is construction-specific
+
+A claim names the exact construction, parameter set, encoding, implementation
+revision, build, platform, key lifecycle, and test evidence. A primitive's
+standardization does not validate its integration.
+
+### CRYPTO-INV-08: Transitions do not negotiate
+
+Old and new suites may overlap only through an authenticated, bounded PKI
+transition. They use separate keys and state. Failure of the new suite does
+not extend, reactivate, or select the old suite.
+
+## 4. Standards Snapshot
+
+The following snapshot is part of the evaluation record. A future activation
+review MUST check for revisions, errata, withdrawals, and implementation
+changes after this date.
+
+| Item | Status used by this evaluation | Relevant consequence |
+| --- | --- | --- |
+| FIPS 203, ML-KEM | final standard; NIST page carries a pending-update note | ML-KEM-768 is the leading standardized KEM parameter set, but errata must be frozen into the implementation review |
+| FIPS 204, ML-DSA | final standard; NIST page carries a pending-update note | ML-DSA-65 is the leading standardized PQ signature component; hedged signing is the production candidate |
+| FIPS 205, SLH-DSA | final standard | useful diversity candidate, but its signatures are too large for the first ordinary PKI suite |
+| NIST SP 800-227 | final, September 2025 | provides KEM-use, key-confirmation, input-validation, ephemeral-key, and composite-KEM guidance |
+| RFC 9794 | informational terminology | separates post-quantum and traditional components without proving a hybrid integration |
+| RFC 9955 | informational hybrid-signature analysis | requires explicit analysis of separability, downgrade, binding, and artifacts |
+| RFC 9980 | proposed-standard OpenPGP profile | provides a deployed standards precedent for ML-DSA-65 plus Ed25519 and ML-KEM-768 plus X25519, but its OpenPGP encoding is not a FOG wire format |
+| X-Wing CFRG draft | Internet-Draft | a serious hybrid KEM candidate, not yet a final general-purpose RFC |
+| PQNoise | reviewed paper and artifact lineage | supports KEM-based Noise analysis, but does not define FOG's required exact entry and mutual-authentication profiles |
+| PQXDH revision 3 | maintained Signal specification | leading asynchronous handshake candidate, with authentication limitations that remain explicit |
+| Double Ratchet revision 4 | maintained Signal specification | defines Triple Ratchet and the Sparse Post-Quantum Ratchet integration |
+| ML-KEM Braid revision 1 | maintained Signal specification | leading continuous post-quantum ratchet component using ML-KEM-768 |
+
+The NIST notes are not license to select whichever behavior an implementation
+happens to expose. Activation pins the standard edition, incorporated errata,
+known-answer tests, and rejection behavior.
+
+## 5. Parameter and Artifact Sizes
+
+These are raw primitive sizes, not complete FOG objects or packets.
+
+| Primitive | Public or encapsulation key | Ciphertext or signature | Secret output or note |
+| --- | ---: | ---: | --- |
+| X25519 | 32 bytes | 32-byte public contribution | 32-byte shared value before protocol KDF |
+| Ed25519 | 32 bytes | 64-byte signature | classical signature component |
+| ML-KEM-768 | 1,184 bytes | 1,088-byte ciphertext | 32-byte shared secret |
+| ML-DSA-65 | 1,952 bytes | 3,309-byte signature | NIST category 3 parameter set |
+| ML-DSA-65 plus Ed25519 | 1,984 bytes | 3,373 bytes | raw component totals before FOG framing |
+| SLH-DSA-SHA2-128s | 32 bytes | 7,856-byte signature | category 1, small public key but large signature |
+
+ML-KEM-768 is the common PQ KEM component advanced across current candidates.
+That reduces implementation diversity, but it does not authorize key reuse or
+a common KEM combiner. Every protocol still has independent keys, transcripts,
+and failure handling.
+
+FOG does not describe the selected parameter sets as one exact symmetric-bit
+security number. Classical and post-quantum categories, multi-user effects,
+protocol composition, implementation leakage, and traffic analysis do not
+collapse honestly to one marketing figure.
+
+## 6. Evaluation Outcome
+
+| Security role | Leading result | Status after this evaluation |
+| --- | --- | --- |
+| PKI object hash | SHA3-256 | first-host benchmark complete, still non-active |
+| PKI signatures | ML-DSA-65 plus Ed25519, both mandatory over one FOG-bound input | first-host benchmark complete, still non-active |
+| KEMSphinx KEM | HPQC ML-KEM-768 plus X25519 split-PRF construction in the already calculated order | first-host complete-packet benchmark complete, still non-active |
+| KEMSphinx remaining primitives | evaluated Katzenpost KDF, MAC, stream, AEZ SPRP, and payload-tag integration | hold pending side-channel, AEZ, multi-host, and complete implementation review |
+| Noise KEM | X-Wing is the leading construction to evaluate | component candidate only |
+| Noise profile | exact PQ entry and mutual-authentication profiles | hold, no FOG profile selected |
+| End-to-end handshake and ratchet | PQXDH revision 3 plus Triple Ratchet revision 4 plus ML-KEM Braid revision 1 | retained and advanced to integration and geometry review |
+| Storage and Composer-local crypto | owned by their candidate specifications | not selected by this document |
+
+Advancing a candidate means that benchmark and integration work may target it.
+It does not mean that a daemon, consensus, bundle, or public claim may use it.
+
+## 7. PKI Hash and Signature Candidate
+
+### 7.1 Candidate records
+
+```text
+hash_candidate_name = FOG-PKI-HASH-CANDIDATE-SHA3-256-1
+hash_suite_id = UNASSIGNED
+hash_output_length = 32
+hash_status = non-active
+
+signature_candidate_name = FOG-PKI-CANDIDATE-MLDSA65-ED25519-1
+signature_suite_id = UNASSIGNED
+signature_status = non-active
+component_order = ML-DSA-65, Ed25519
+verification_rule = ALL_COMPONENTS_REQUIRED
+```
+
+SHA3-256 preserves the existing 32-byte identifier widths and avoids a
+length-extension interface. Its selection is still candidate-level because
+FOG must publish byte-exact vectors for every PKI domain and measure its
+implementation on every authority and consumer class.
+
+ML-DSA-65 plus Ed25519 is advanced because:
+
+- both components have stable standardized definitions;
+- the parameter pair has a current standards precedent in RFC 9980;
+- ML-DSA-65 and ML-KEM-768 target the same NIST category without selecting the
+ larger category-5 signature for every consensus object;
+- Ed25519 is compact and widely implemented;
+- requiring both components avoids a success path that silently becomes only
+ classical or only post-quantum.
+
+RFC 9980 is evidence for the parameter pairing, not the FOG encoding. FOG
+does not copy OpenPGP packets, prehash rules, algorithm identifiers, or key
+material formats.
+
+### 7.2 Key representation
+
+One FOG composite public-key record contains two independently generated
+public keys in the fixed order ML-DSA-65, then Ed25519. One signature value
+contains two exact-length signatures in that same order.
+
+The eventual PKI profile MUST define a fixed-length array rather than a raw
+concatenated byte string. It MUST reject missing, duplicated, reordered,
+trailing, unknown, or incorrectly sized components before verification.
+
+Key identifiers cover the complete candidate suite ID and complete composite
+public-key encoding. A component key ID is not a substitute for the composite
+key ID. Components from different records, subjects, authorities, purposes,
+or validity intervals cannot be assembled into one valid key.
+
+### 7.3 Verification rule
+
+Both component signatures MUST validate over the identical exact FOG
+signature input using the public keys in the one already trusted composite
+key record. There is no threshold inside a signature and no partial success.
+
+Verification evaluates both components using an implementation strategy whose
+remote timing does not disclose which component failed. The final result is
+one success or one coarse authentication failure. Parser and key-record errors
+are checked before signature work but do not produce component-specific remote
+responses.
+
+### 7.4 Suite binding and separability
+
+The signature suite ID MUST be inside the signed input. The FOG-PKI signature
+input is therefore:
+
+```text
+[
+ "FOG-PKI-SIGNATURE-1",
+ network_id,
+ object_type,
+ signature_suite_id,
+ signed_object_bytes
+]
+```
+
+This corrects the earlier structural draft, in which `signature_suite_id`
+appeared only in the outer `SignatureRecord`. Without this binding, one valid
+component could be extracted and presented to a profile that accepted that
+component alone over the same bytes.
+
+Binding the suite ID supplies the weak non-separability property described by
+RFC 9955 when combined with exact key purpose, all-component verification, and
+no fallback. It does not establish strong non-separability. Before activation,
+FOG MUST publish an artifact analysis covering at least:
+
+- component stripping and rewrapping;
+- cross-suite and cross-protocol reuse;
+- key substitution and component recombination;
+- duplicate or reordered components;
+- mixed old and new profile records during transition;
+- verification differences across implementations;
+- exposure of a component signature outside FOG.
+
+FOG MUST NOT activate a classical-only signature suite that accepts an
+extracted component under a compatible transcript during the candidate's
+validity or drain interval.
+
+### 7.5 Signing randomness
+
+Production ML-DSA-65 signing uses the hedged variant with a fresh 32-byte
+random value from the approved operating-system randomness source for every
+signature operation. Deterministic signing is reserved for fixed conformance
+vectors and explicit failure testing, not normal authority operation.
+
+Randomness failure stops signing. It does not select deterministic mode.
+Ed25519 and ML-DSA component keys are independently generated and stored.
+
+### 7.6 Implementation candidates
+
+For a Go implementation, the standard `crypto/ed25519` package is the leading
+Ed25519 component. Cloudflare CIRCL version 1.6.5 is a candidate source for
+ML-DSA-65 and X-Wing evaluation because it is versioned, has known-answer
+tests, and documents package-level review expectations.
+
+CIRCL's own project description still treats deployment conservatively and
+does not make every package or integration constant-time by declaration.
+Activation therefore pins the exact module version and package paths, audits
+attacker-controlled panic paths and secret-dependent behavior, reproduces
+FIPS vectors, and records the license and dependency graph.
+
+### 7.7 Alternatives not advanced
+
+- ML-DSA-44 is smaller but targets a lower category than the leading FOG
+ candidate.
+- ML-DSA-87 increases every signature and public key without a demonstrated
+ FOG need for category 5 in the first profile.
+- SLH-DSA provides valuable design diversity but a 7,856-byte 128s signature
+ is costly for frequently signed PKI objects and update bundles. It remains a
+ future root, release, or diversity study, not the first ordinary suite.
+- NIST's additional-signature candidates and HQC are still undergoing
+ standardization work. They are tracked, not placed into an active profile.
+- A classical-only signature is useful for isolated development tests only if
+ it has a separately named profile and no automatic relationship to the
+ claim-bearing network.
+
+## 8. Hybrid KEM Requirements
+
+FOG treats a hybrid KEM as a complete construction, not as two KEM names and a
+concatenation operator. Its immutable definition includes:
+
+- component algorithms and parameter sets;
+- component key and ciphertext encodings;
+- generation independence;
+- component order;
+- combiner function;
+- exact combiner input encoding and domain;
+- public context bound by the combiner;
+- malformed-key and malformed-ciphertext behavior;
+- implicit-rejection and failure semantics;
+- shared-secret length;
+- key-confirmation responsibility;
+- test vectors and implementation revision.
+
+NIST SP 800-227 requires the complete composite-KEM construction to receive
+analysis. It also recommends explicit, unambiguous inputs and key confirmation
+where the protocol requires assurance that both parties derived the same key.
+FOG follows that guidance at the owning protocol boundary.
+
+No FOG code may expose an API equivalent to:
+
+```text
+CombineAnyKEMs(list_of_names, raw_concatenated_values)
+```
+
+Each reviewed construction instead has a compile-time adapter with exact
+types, lengths, domains, and failure behavior.
+
+## 9. KEMSphinx Candidate
+
+### 9.1 Retained construction
+
+The existing packet candidate remains:
+
+```text
+FOG-SPHINX-CANDIDATE-MLKEM768-X25519-1
+```
+
+It uses the evaluated HPQC security-preserving split-PRF hybrid construction
+with X25519 hashed-ElGamal first and ML-KEM-768 second. The display name does
+not define component order. The exact registry record and test vectors do.
+
+The hybrid ciphertext is 1,120 bytes:
+
+```text
+X25519 hashed-ElGamal ciphertext 32
+ML-KEM-768 ciphertext 1088
+total 1120
+```
+
+The complete already calculated four-hop FOG packet remains 16,150 bytes,
+with a 4,096-byte user payload and a 6,058-byte public SURB. This evaluation
+does not change a byte of that geometry.
+
+### 9.2 Why X-Wing does not silently replace it
+
+X-Wing is a strong general hybrid-KEM candidate, and RFC 9980 contains a
+QSF/X-Wing-compatible ML-KEM-768 plus X25519 construction for OpenPGP. That
+does not prove interchangeability inside KEMSphinx.
+
+KEMSphinx needs a hybrid KEM with the security properties required by its
+packet proof and active-attacker model. The maintained Katzenpost KEMSphinx
+specification explicitly warns that a hybrid construction designed for a
+handshake protocol is not automatically suitable unless it provides the
+required robust IND-CCA behavior.
+
+Replacing the split-PRF construction with X-Wing would create a newly named
+packet candidate, new header bytes, new vectors, and a new proof and
+implementation review. It cannot keep this candidate name or geometry record
+by convenience.
+
+### 9.3 Evidence and implementation risks
+
+The HPQC repository supplies the exact split-PRF construction, X25519 adapter,
+ML-KEM-768 implementation bindings, and KEMSphinx-oriented interfaces. It also
+describes itself as experimental and states that it has not received an
+external security review. No stable release line is assumed by FOG.
+
+The candidate therefore pins an exact source commit and transitive dependency
+set. Its AGPL-3.0 licensing must be compatible with the future FOG repository
+and distribution model before adoption.
+
+The rest of the evaluated Katzenpost packet suite, including KDF, header MAC,
+header stream, AEZ-based payload SPRP, and payload-tag construction, remains
+under review. AEZ's age and small implementation ecosystem make complete
+vectors, misuse analysis, constant-time inspection, fuzzing, and an
+independent review mandatory. Geometry compatibility is not primitive
+approval.
+
+### 9.4 Benchmark admission
+
+The candidate is admitted to complete-packet benchmarking because its exact
+ciphertext sizes and packet arithmetic are known. It remains non-active until
+the gates in `FOG-SPHINX-PROFILES.md` and this document pass.
+
+## 10. Adjacent-Link Noise Evaluation
+
+### 10.1 Required FOG semantics
+
+FOG-WIRE needs at least two exact post-quantum link profiles:
+
+1. entry mode, where the blind relay authenticates the entry without exposing
+ a stable relay Noise identity;
+2. mutual node mode, where both authorized adjacent roles authenticate each
+ other and the PKI-bound role and key context.
+
+Both profiles must preserve the existing fixed preface, authenticated
+prologue, empty application payload during the handshake, fixed encrypted
+records, standard Noise message bound, no 0-RTT, no resumption, and no runtime
+negotiation.
+
+### 10.2 Evidence reviewed
+
+The PQNoise paper gives a reviewed method for replacing Noise DH operations
+with KEM operations and analyzes the resulting protocol family. Katzenpost's
+current wire specification gives concrete operational experience with
+`Noise_pqXX_Xwing_ChaChaPoly_BLAKE2b`.
+
+That Katzenpost profile is not adopted directly because:
+
+- its `pqXX` authentication sequence is not the exact FOG entry or mutual
+ pattern already specified;
+- FOG entry mode must avoid a stable initiator identity;
+- FOG mutual mode is bound to exact PKI roles and adjacency;
+- Katzenpost's nonstandard large Noise-message allowance is unnecessary for
+ FOG's empty-handshake-payload rule;
+- FOG has its own preface, prologue, record, command, epoch, and transition
+ contract.
+
+### 10.3 Result
+
+X-Wing is the leading KEM construction to evaluate for FOG-WIRE because it
+combines ML-KEM-768 and X25519 with a fixed analyzed combiner and has both a
+current CFRG draft and maintained implementations. It is not yet a selected
+FOG-WIRE profile.
+
+No exact hybrid post-quantum Noise profile is advanced in this evaluation.
+FOG will not create `pqNK` or `pqKK` pattern names without a reviewed
+specification, transcript definition, state-machine analysis, vectors, and a
+maintained library that supports the required semantics.
+
+Classical Noise profiles may be used in an isolated functional PoC only under
+separate explicit names and claims. They are not fallback profiles and cannot
+produce a post-quantum or public-alpha security claim.
+
+### 10.4 Noise activation requirements
+
+Before selecting a numeric wire profile, FOG MUST have:
+
+- an exact reviewed entry handshake with responder authentication and no
+ stable initiator identity;
+- an exact reviewed mutual handshake;
+- exact protocol names, token sequences, transcript hashes, KEM operations,
+ combiner inputs, cipher, hash, prologue processing, and message limits;
+- deterministic positive and negative vectors for both roles;
+- identity-misbinding, unknown-key-share, downgrade, replay, reflection,
+ malformed-ciphertext, and component-failure analysis;
+- key confirmation and channel-binding analysis;
+- a maintained implementation or a separately reviewed implementation plan;
+- byte, CPU, memory, handshake-flood, and side-channel benchmarks;
+- independent review of the exact FOG integration.
+
+Until then, `FOG-WIRE.md` remains structurally complete but cryptographically
+non-active.
+
+## 11. End-to-End Messaging Candidate
+
+### 11.1 Retained construction
+
+The leading messaging integration remains:
+
+```text
+FOG-MSG-CANDIDATE-PQXDH-TR-MLKEM768-1
+```
+
+It pins:
+
+- PQXDH revision 3 for asynchronous session initiation;
+- Double Ratchet revision 4 Triple Ratchet;
+- ML-KEM Braid revision 1 using ML-KEM-768;
+- one-time classical and signed one-time ML-KEM prekeys;
+- no reusable last-resort PQ prekey in a claim-bearing profile;
+- the fixed FOG envelope, voucher, storage, retry, and transaction contracts.
+
+This is the strongest maintained end-to-end candidate found that matches
+FOG's asynchronous, intermittently transferred Composer state without
+inventing a ratchet.
+
+### 11.2 Claim boundaries
+
+The candidate does not by itself establish post-quantum authentication.
+PQXDH revision 3 retains classical authentication assumptions. An outer FOG
+PKI or pairwise-root signature does not silently rewrite PQXDH's proof or
+turn its authentication into a post-quantum property.
+
+Triple Ratchet combines a classical Double Ratchet and the Sparse
+Post-Quantum Ratchet. Post-quantum post-compromise recovery depends on fresh
+ratchet progress. Dropped, delayed, reordered, or never-returning traffic can
+delay or prevent the expected recovery boundary.
+
+FOG also withholds deniability, safe backup, multi-device convergence, group
+security, and complete geometry claims until the exact integration is tested.
+
+### 11.3 Implementation evidence and risk
+
+Signal publishes the PQXDH, Double Ratchet, and ML-KEM Braid specifications.
+The Sparse Post-Quantum Ratchet repository includes Rust code and formal
+artifacts, including hax/F* and ProVerif work. This is useful evidence, not a
+release or support promise for FOG.
+
+The broader `libsignal` repository is production software for Signal's own
+clients, but its public documentation warns that external use is unsupported
+and APIs may change. Its AGPL licensing, Rust integration boundary, release
+pinning, unsupported external API status, and transitive dependency surface
+must be resolved before selection.
+
+FOG will choose one of two explicit paths after a spike and license review:
+
+1. pin a reviewed Rust implementation behind a minimal memory-safe interface
+ with ownership, zeroization, panic, and serialization tests; or
+2. implement the exact published construction using reviewed primitives and
+ reproduce upstream plus FOG integration vectors.
+
+A partial port, altered KDF, altered transcript, changed ratchet combination,
+or locally simplified loss behavior is a new candidate, not this one.
+
+### 11.4 Integration work admitted
+
+The candidate advances to byte-exact envelope and packet-geometry work. The
+next benchmark must include PQXDH initiation, ongoing Triple Ratchet headers,
+ML-KEM Braid state and ciphertexts, skipped-key bounds, storage framing, and
+fragmentation against the exact 4,096-byte KEMSphinx user payload.
+
+## 12. Storage and Composer Boundary
+
+This evaluation does not select the `FOG-STORAGE` or `FOG-COMPOSER` local
+cryptographic profiles. Their candidates have different properties:
+
+- capability derivation and authenticated storage requests;
+- object-level vault AEAD and key wrapping;
+- passphrase KDF and platform memory limits;
+- backup and recovery encryption;
+- update and release authentication.
+
+Those profiles may reuse a standardized primitive only through independent
+suite records and purpose-separated keys. They do not inherit the PKI,
+KEMSphinx, Noise, or messaging suite identifier.
+
+## 13. Implementation Architecture
+
+The future source tree SHOULD isolate construction-specific adapters by
+security role, for example:
+
+```text
+internal/crypto/pki/
+internal/crypto/kemsphinx/
+internal/crypto/wire/
+internal/crypto/messaging/
+internal/crypto/testvectors/
+```
+
+The shared layer may contain only inert metadata types, constant-time utility
+wrappers whose behavior is independently reviewed, randomness interfaces, and
+test-vector loading. It does not contain a generic negotiate-and-dispatch
+registry or accept algorithm names from the network.
+
+Each executable imports only the operations required by its role. In
+particular:
+
+- a mix does not import PKI signing or messaging secret operations;
+- an authority does not import KEMSphinx decapsulation for mix processing;
+- a blind relay does not import Composer message decryption;
+- a Composer does not import online authority signing;
+- a bridge does not receive core private-key handles.
+
+Secret-bearing types should be non-copyable where the implementation language
+permits it. Serialization APIs are private to the owning persistence or
+descriptor boundary. Ordinary application APIs do not return raw private
+keys.
+
+## 14. Dependency and Supply-Chain Record
+
+Every candidate benchmark and later activation records:
+
+- upstream repository and canonical source location;
+- exact tag and commit;
+- standard edition and incorporated errata;
+- module and transitive dependency lock;
+- checksums and reproducible build procedure;
+- implementation language and compiler version;
+- license and redistribution analysis;
+- known audit, review, issue, and vulnerability status;
+- known-answer and cross-implementation vector results;
+- target operating systems, architectures, and CPU feature paths;
+- constant-time and attacker-controlled panic review;
+- generated SBOM and release provenance.
+
+An untagged dependency may be benchmarked by commit. It cannot be activated
+without an explicit maintenance and update policy. A repository being active
+does not replace a cryptographic or side-channel review.
+
+## 15. Randomness, Secret Memory, and Failure
+
+### 15.1 Randomness
+
+All production key generation, ML-KEM encapsulation, ML-DSA hedged signing,
+ephemeral handshake operations, and packet creation use the approved
+operating-system randomness source through one narrow injectable interface.
+Deterministic entropy is available only in test builds or explicit vector
+tools.
+
+Short reads, unavailable randomness, health-test failure, fork duplication,
+or impossible state stop the operation. No protocol silently repeats a seed,
+switches to time-based randomness, or changes to deterministic mode.
+
+### 15.2 Secret lifetime
+
+The owning specifications define durable lifetime. At the implementation
+boundary:
+
+- ephemeral KEM and DH private material is single-use where the construction
+ requires it;
+- retired shared secrets and message keys are released promptly;
+- error, metrics, tracing, panic, and crash paths never format secret bytes;
+- core dumps and swap are addressed by the deployment profile;
+- zeroization claims are limited to memory actually controlled by the
+ implementation and compiler;
+- immutable language copies and allocator remnants remain documented limits.
+
+### 15.3 Remote behavior
+
+The implementation may keep coarse local counters such as malformed length,
+authentication failure, resource limit, or internal failure. It never logs a
+key, ciphertext content, transcript, message identifier, capability, route,
+or component-specific decapsulation result.
+
+Externally, failures follow the owning protocol's uniform drop, close, or
+fixed response. A second algorithm is never tried after failure.
+
+## 16. Benchmark Contract
+
+The benchmark phase measures complete protocol operations, not primitive
+microbenchmarks alone. `FOG-CRYPTO-BENCHMARKS.md` records the first-host
+implementation baseline. That partial completion does not relax the remaining
+hardware, operation, review, or activation requirements below.
+
+### 16.1 Required hardware classes
+
+At minimum, publish results for:
+
+- the lowest supported x86-64 class without optional acceleration assumptions;
+- a current x86-64 server class;
+- the lowest supported ARM64 Composer or node class;
+- the intended offline Composer hardware class.
+
+Every result names the CPU, microcode, OS, compiler, power mode, dependency
+commit, feature flags, iteration count, warmup, and raw result artifact.
+
+### 16.2 Required measurements
+
+For every applicable role, measure:
+
+- key generation, encapsulation, decapsulation, signing, and verification;
+- complete four-hop packet create and each hop unwrap;
+- complete SURB creation, reply creation, and final reply decryption;
+- entry and mutual Noise handshake candidates when available;
+- PQXDH initiation and steady-state Triple Ratchet send and receive;
+- allocation count, peak live memory, stack use, binary-size contribution,
+ and persistent key size;
+- success, malformed, and cryptographic-failure paths;
+- concurrent throughput and tail latency under bounded adversarial load;
+- descriptor, consensus, update-bundle, envelope, record, SURB, and packet
+ byte costs;
+- queue, cover-traffic, storage, and bandwidth consequences of the exact
+ complete geometry.
+
+Primitive results are retained for diagnosis, but profile selection uses the
+complete-operation figures.
+
+### 16.3 Side-channel checks
+
+The benchmark harness also runs or records:
+
+- secret-dependent branch and memory-access review for exact package paths;
+- dudect-style timing tests where applicable;
+- malformed-input timing distributions;
+- CPU-feature and fallback-path equivalence;
+- race, sanitizer, fuzz, and attacker-controlled panic results;
+- cross-process isolation assumptions for co-located PoC roles.
+
+Passing statistical tests is evidence, not proof of constant-time behavior.
+
+### 16.4 First-host baseline
+
+The pinned Go harness in `../benchmarks/crypto/` completed the first older
+x86-64 baseline for SHA3-256, composite PKI operations, candidate KEMs, and the
+exact four-hop 16,150-byte KEMSphinx request/reply path.
+
+The full request/reply cryptographic operation measured about 8.89 ms at the
+median, with about 638 KiB and 1,452 allocations per operation. Direct use of
+the parameterized maintained `Unwrap` API did not enforce FOG's exact external
+packet length, so the harness adds a typed FOG boundary that rejects all
+non-exact paths, packets, payloads, SURBs, encrypted replies, and reply-key
+blocks before cryptographic processing.
+
+The result retains the evaluated candidates without activating them. Raw
+three-sample data, environment details, exact sizes, exclusions, and observed
+timing variability are in
+`../benchmarks/crypto/results/2026-08-08-x86-64-i5-6300u.md`.
+
+## 17. Activation and Retirement
+
+A candidate can receive a numeric ID only after:
+
+1. its complete immutable record and encoding are published;
+2. the owning protocol's geometry and state machine are byte-exact;
+3. at least two independently integrated implementations reproduce positive
+ and negative vectors where the protocol gate requires them;
+4. dependencies, licenses, builds, randomness, failures, side channels, key
+ lifecycle, and resource limits are reviewed;
+5. complete-operation benchmarks fit the supported hardware and cover model;
+6. transition, rollback, revocation, compromise, and retirement behavior is
+ tested;
+7. protocol and implementation review findings are resolved or explicitly
+ accepted with bounded claims;
+8. a decision record names the profile and its permitted deployment stage.
+
+Activation is monotonic. A newly discovered vulnerability can stop creation
+or acceptance, but cannot trigger an unauthenticated downgrade. Emergency
+retirement may cause message, packet, or availability loss.
+
+## 18. Claims Deliberately Withheld
+
+This evaluation does not support the following statements:
+
+- FOG is post-quantum secure.
+- A hybrid is secure whenever either component remains secure.
+- ML-KEM inclusion makes authentication post-quantum.
+- ML-DSA plus Ed25519 is strongly non-separable.
+- KEMSphinx geometry proves packet security or anonymity.
+- PQNoise research already supplies FOG's exact Noise profiles.
+- Signal's specifications validate FOG framing, persistence, loss, backup, or
+ offline transfer behavior.
+- a memory-safe language eliminates side channels, secret copies, panics, or
+ protocol errors.
+- NIST standardization or a maintained repository replaces independent
+ integration review.
+
+Public wording must name the exact active profile and evidence, or state that
+the construction is a non-active research candidate.
+
+## 19. Open Work After This Evaluation
+
+The following items remain before any cryptographic profile can become active:
+
+- publish the exact FOG PKI composite-key and signature-component encoding;
+- produce SHA3-256 domain vectors and the full PKI signature artifact analysis;
+- decide the implementation and license path for ML-DSA-65;
+- audit the pinned HPQC, Katzenpost, and AEZ dependency set;
+- repeat complete 16,150-byte KEMSphinx packet, SURB, and persistent replay
+ benchmarks on current server, ARM64, and offline Composer hardware;
+- select or produce a reviewed exact FOG entry and mutual PQNoise profile;
+- complete the PQXDH, Triple Ratchet, ML-KEM Braid, FOG envelope, and storage
+ serialization and state integration;
+- measure all candidates against complete packet, wire, bundle, and storage
+ geometry;
+- publish deterministic and negative vectors and independent review results;
+- revisit standards, drafts, errata, and implementation status at activation.
+
+## 20. Primary References
+
+- NIST FIPS 203, ML-KEM:
+ <https://csrc.nist.gov/pubs/fips/203/final>
+- NIST FIPS 204, ML-DSA:
+ <https://csrc.nist.gov/pubs/fips/204/final>
+- NIST FIPS 205, SLH-DSA:
+ <https://csrc.nist.gov/pubs/fips/205/final>
+- NIST SP 800-227, Recommendations for Key-Encapsulation Mechanisms:
+ <https://csrc.nist.gov/pubs/sp/800/227/final>
+- RFC 9794, Terminology for Post-Quantum Traditional Hybrid Schemes:
+ <https://www.rfc-editor.org/rfc/rfc9794.html>
+- RFC 9955, Hybrid Signature Spectrums:
+ <https://www.rfc-editor.org/rfc/rfc9955.html>
+- RFC 9980, Post-Quantum Cryptography in OpenPGP:
+ <https://www.rfc-editor.org/rfc/rfc9980.html>
+- CFRG X-Wing KEM Internet-Draft:
+ <https://datatracker.ietf.org/doc/draft-connolly-cfrg-xwing-kem/>
+- PQNoise:
+ <https://eprint.iacr.org/2022/539>
+- Katzenpost wire protocol:
+ <https://katzenpost.network/docs/specs/wireprotocol/>
+- Katzenpost KEMSphinx specification:
+ <https://katzenpost.network/docs/specs/kemsphinx/>
+- Katzenpost HPQC implementation:
+ <https://github.com/katzenpost/hpqc>
+- Katzenpost AEZ implementation:
+ <https://github.com/Yawning/aez>
+- Signal PQXDH revision 3:
+ <https://signal.org/docs/specifications/pqxdh/>
+- Signal Double Ratchet revision 4:
+ <https://signal.org/docs/specifications/doubleratchet/>
+- Signal ML-KEM Braid revision 1:
+ <https://signal.org/docs/specifications/mlkembraid/>
+- Signal Sparse Post-Quantum Ratchet implementation:
+ <https://github.com/signalapp/sparsepostquantumratchet>
+- Signal libsignal implementation:
+ <https://github.com/signalapp/libsignal>
+- Cloudflare CIRCL:
+ <https://github.com/cloudflare/circl>
+- Go ML-KEM package:
+ <https://pkg.go.dev/crypto/mlkem>
+- FOG threat model: `FOG-THREAT-MODEL.md`
+- FOG architecture: `FOG-ARCHITECTURE.md`
+- FOG PKI: `FOG-PKI.md`
+- FOG wire protocol: `FOG-WIRE.md`
+- FOG KEMSphinx profiles: `FOG-SPHINX-PROFILES.md`
+- FOG messaging: `FOG-MESSAGING.md`
+- FOG cryptographic benchmark baseline: `FOG-CRYPTO-BENCHMARKS.md`
+
+These sources support the shortlist and its constraints. The exact FOG
+composition still requires its own vectors, tests, benchmarks, operational
+analysis, and independent review.
diff --git a/docs/FOG-LOCAL-POC.md b/docs/FOG-LOCAL-POC.md
new file mode 100644
index 0000000..d156e10
--- /dev/null
+++ b/docs/FOG-LOCAL-POC.md
@@ -0,0 +1,345 @@
+# FOG Local Podman PoC
+
+Status: Runnable Fixture 0.2
+
+Date: 2026-08-08
+
+## 1. Purpose and Claim Boundary
+
+`FOG-LOCAL-POC-1` is the first runnable local process, isolation, baseline,
+and failure-test boundary for FOG. It turns the architecture's role and
+reachability rules into a validated rootless Podman fixture.
+
+The machine-readable artifacts and validator are in `../deploy/podman/`.
+
+This definition is functional evidence only. It cannot demonstrate operator
+independence, infrastructure diversity, an anonymity set, traffic-analysis
+resistance, availability, capacity, production key handling, or a safe
+numeric protocol profile. All containers run on one host under one user and
+therefore share a host kernel, storage stack, management account, clock, and
+failure domain.
+
+The fixture does not activate FOG-WIRE, FOG-PKI, KEMSphinx, storage,
+messaging, cover, delay, polling, retry, or degraded-mode parameters. It does
+not implement or substitute for any protocol daemon. Its deliberately bounded
+and non-cryptographic transport is named `FOG-POC-FIXTURE-1`.
+
+## 2. Requirements
+
+The PoC definition is governed by:
+
+- `ARC-001`, separate trust domains even when co-located;
+- `ARC-002`, a networkless Composer;
+- `ARC-003`, no data-plane bypass;
+- `ARC-005`, complete authenticated network views;
+- `ARC-007`, one private-key owner and no shared writable state;
+- `ARC-008`, bounded configuration, work, and state;
+- `ARC-009`, no privacy-weakening fallback;
+- `IF-06` through `IF-09`, exact online data-plane adjacencies;
+- `TM-NET-03`, `TM-NET-04`, `TM-PKI-02`, `TM-PKI-03`,
+ `TM-ROLE-01`, `TM-ROLE-02`, `TM-ROLE-03`, `TM-CRYPTO-01`, and
+ `TM-AVAIL-01`;
+- `PKI-INV-01`, `PKI-INV-03`, `PKI-INV-04`, and `PKI-INV-08`;
+- `WIRE-INV-07`, `WIRE-INV-08`, `WIRE-INV-09`, and `WIRE-INV-10`.
+
+Podman 5.8.3 and podman-compose 1.6.0 are present on the first local host. The
+runtime contract targets rootless Podman and internal bridge networks. Podman
+documents `network=none` as a network namespace without configured network
+interfaces and an internal bridge as restricting external access. These
+runtime properties remain acceptance-test subjects rather than assumptions.
+
+## 3. Deployment Stages
+
+### 3.1 Definition stage, completed
+
+The checked-in JSON plan and standard-library Go validator define roles,
+network edges, private state ownership, container hardening, resource
+containment, and the mandatory fault matrix.
+
+This stage prevented placeholder ports, fake cryptography, reusable example
+keys, or an unreviewed generic fixture protocol from becoming accidental
+implementation defaults.
+
+### 3.2 Fixture stage, current
+
+The executable harness provides explicitly named PoC-only binaries. They
+exercise process lifecycle, exact opaque object geometry, network
+reachability, bounded connections and work, restart behavior, role-local
+state, secret isolation, and fault outcomes. They do not call their transport
+FOG-WIRE or their public data FOG-PKI.
+
+The stage builds one scratch image without build-time networking, addresses it
+by its local OCI manifest digest, and deterministically generates a Compose
+manifest from validated `topology.json`. The internal TCP port `17001` belongs
+only to the fixture harness and is not a selected FOG protocol port.
+
+### 3.3 Protocol-functional stage
+
+Actual role executables replace the fixtures only after the relevant exact
+profiles, libraries, parsers, key formats, and conformance vectors are
+selected. Each replacement must retain the same state and network ownership
+contract and pass the same fault matrix.
+
+## 4. Role Inventory
+
+| Instance | Executable contract | Purpose | Network state |
+| --- | --- | --- | --- |
+| `composer-fixture` | `fog-poc-composer-fixture` | Networkless public-fixture acceptance state | `none` |
+| `authority-fixture` | `fog-poc-authority-fixture` | Networkless authority-condition state | `none` |
+| `relay` | `fog-client-relay` | Opaque client queue and entry submission | private pairwise network |
+| `entry` | `fog-entry` | Entry boundary outside the mix layers | two private pairwise networks |
+| `mix-l1` | `fog-mix`, fixed layer 1 | First mix position | two private pairwise networks |
+| `mix-l2` | `fog-mix`, fixed layer 2 | Second mix position | two private pairwise networks |
+| `mix-l3` | `fog-mix`, fixed layer 3 | Third mix position | two private pairwise networks |
+| `courier` | `fog-courier` | Terminal request and replica mediation | five private pairwise networks |
+| `store-a` through `store-d` | `fog-store` | Four separate storage fixtures | one private pairwise network each |
+
+The three-node description refers to the three fixed mix positions. Entry and
+courier remain outside those three KEMSphinx delay layers. Four storage
+containers exist so the PoC does not normalize a smaller shared storage
+fixture into the intended architecture.
+
+The authority and Composer fixtures are networkless process and state
+boundaries. Fault flags model only coarse acceptance states such as quorum
+loss or conflicting public fixtures. They do not create signatures,
+consensus objects, identities, contacts, capabilities, or message secrets and
+supply no authority-independence claim.
+
+An observer is not in this first topology. `FOG-OBSERVABILITY-1` now defines
+the separate structural logging and aggregate contract, but no observer,
+numeric observability profile, or IF-11 codec is active in this fixture. No
+container may substitute ordinary logs or packet traces for `fog-observer`.
+
+## 5. Network Segmentation
+
+Every declared network is internal and contains exactly two roles:
+
+```text
+relay <-> entry <-> mix-l1 <-> mix-l2 <-> mix-l3 <-> courier
+ |-- store-a
+ |-- store-b
+ |-- store-c
+ `-- store-d
+```
+
+The nine networks are:
+
+| Network | Members | Interface |
+| --- | --- | --- |
+| `relay-entry` | relay, entry | `IF-06` |
+| `entry-l1` | entry, mix-l1 | `IF-07` |
+| `l1-l2` | mix-l1, mix-l2 | `IF-07` |
+| `l2-l3` | mix-l2, mix-l3 | `IF-07` |
+| `l3-courier` | mix-l3, courier | `IF-08` |
+| `courier-store-a` | courier, store-a | `IF-09` |
+| `courier-store-b` | courier, store-b | `IF-09` |
+| `courier-store-c` | courier, store-c | `IF-09` |
+| `courier-store-d` | courier, store-d | `IF-09` |
+
+There is no shared data-plane bridge. No role uses the host network. No
+container port is published to the host. The Composer and authority fixtures
+use `network=none`. Coarse public-data failure conditions are written only to
+the targeted role's private fixture state and contain no consensus bytes or
+cryptographic material.
+
+The runnable harness proves that containers cannot reach an
+external address, host-local services, or undeclared roles. Name resolution
+success is not sufficient evidence of an authorized protocol edge, and
+failure of one edge must never create another.
+
+## 6. Filesystem, Keys, and Container Hardening
+
+Every role-container contract requires:
+
+- rootless execution as a dedicated non-root container user;
+- one digest-pinned immutable image;
+- a read-only root filesystem;
+- `no-new-privileges`;
+- all Linux capabilities dropped;
+- no privileged mode, device passthrough, host PID, host IPC, host UTS, or
+ host network namespace;
+- private `/run` and `/tmp` tmpfs mounts with bounded sizes in the generated
+ manifest;
+- exactly one role-owned writable state volume;
+- no source checkout, container socket, generic host directory, or other
+ role's state mounted;
+- disabled core dumps and no secret-bearing diagnostic output;
+- explicit CPU, memory, PID, file-descriptor, connection, and queue limits.
+
+The checked-in CPU, memory, and PID values are harness containment limits, not
+capacity results or protocol profile parameters. Their only purpose is to
+make local fault tests bounded.
+
+One 32-byte non-cryptographic fixture token per role is generated in memory
+from the operating-system CSPRNG. It is streamed into a distinct Podman Secret
+object. The installed `podman-compose` plus `runc` combination cannot mount
+that file directly into a read-only role root filesystem, so a networkless,
+bounded, one-shot stager copies it into a newly created role-specific volume
+with mode `0400`. The Podman Secret source is removed immediately and the role
+mounts only its own secret volume read-only.
+
+Tokens never enter source, JSON plans, images, host-supplied files, command
+arguments, environment templates, logs, test reports, or public fixture objects. A
+constant-time runtime challenge confirms that each role received its intended
+token without reporting a value or digest. Teardown removes the disposable
+secret and state volumes. Destruction of the `mix-l2` replay fixture requires
+the separate `--allow-destructive` option and names the exact target first.
+
+## 7. Baseline Functional Flow
+
+The runnable fixture performs these steps from clean role state:
+
+1. Start the Composer and authority process fixtures without a configured
+ network interface and validate their private state and token scope.
+2. Generate one opaque fixed-size packet fixture with the current 16,150-byte
+ candidate geometry, clearly labeled as non-cryptographic PoC data.
+3. Admit the fixture only at relay, then traverse entry, mix-l1, mix-l2,
+ mix-l3, and courier in that order.
+4. Dispatch one bounded opaque operation from courier to the storage fixture
+ set and collect only the modeled receipt result.
+5. Return a bounded opaque result through the declared reverse adjacency,
+ without creating a direct courier-to-relay connection.
+6. Verify that no role mounted another role's state or token and that no
+ container gained an undeclared network.
+7. Report only the role names, scenario IDs, and coarse fixture outcomes.
+
+The successful first-host result is `complete-fixture`, four modeled fixture
+receipts, and four fixture hops after entry. These counts describe only this
+test transport and must not be read as storage durability or anonymity
+evidence.
+
+The harness keeps no packet transcript. Container logging is disabled and no
+result contains packet bytes, object identifiers, per-packet timing, keys,
+route secrets, capabilities, or source addresses.
+
+## 8. Fault Matrix
+
+`fault-scenarios.json` defines fifteen mandatory scenarios:
+
+| Scenario | Expected invariant |
+| --- | --- |
+| `forbidden-role-edge` | Only declared pairwise reachability exists |
+| `entry-stop` | No relay-to-layer-1 fallback |
+| `mix-layer-two-stop` | No layer skip or courier delivery |
+| `layer-two-three-partition` | Bounded failure on the same adjacency |
+| `mix-replay-state-loss` | Same-epoch processing fails closed |
+| `stale-consensus` | New work stops at hard expiry |
+| `same-epoch-consensus-fork` | Consumers freeze instead of choosing a view |
+| `authority-quorum-loss` | Partial views and insufficient signatures fail |
+| `clock-uncertainty` | Time-sensitive acceptance stops |
+| `single-store-loss` | No false durability result |
+| `receipt-quorum-loss` | Required receipts cannot be fabricated |
+| `courier-stop` | No layer-3 or client connection to storage |
+| `entry-handshake-flood` | Work and responses remain bounded |
+| `cover-process-stop` | A cover-dependent claim cannot continue silently |
+| `role-secret-isolation` | No cross-role state or fixture-token access |
+
+Each scenario names target roles, the abstract action, expected behavior,
+explicitly prohibited fallback, requirement IDs, automation status, and
+whether it mutates role state. Abstract actions deliberately contain no shell
+command. The fault runner resolves container and volume targets
+from the validated plan, show destructive targets before execution, and start
+state-destructive tests from disposable snapshots.
+
+No scenario may run concurrently with another. Each begins from a documented
+clean baseline so an earlier partition, stopped role, or modified volume
+cannot make a later test pass for the wrong reason.
+
+On the first host, all fourteen automatable scenarios pass. The
+`cover-process-stop` row remains `not-automatable`: the fixture has no cover
+scheduler and therefore cannot silently retain a cover or unobservability
+claim. The effective runtime verifier completes 239 checks before the fault
+matrix begins.
+
+## 9. Acceptance Gates
+
+### 9.1 Definition gate, satisfied
+
+- The strict parser accepts the checked-in topology and fault plan.
+- Duplicate or unknown fields, trailing JSON, oversized or non-regular inputs
+ fail.
+- Required roles, exact mix layers, four stores, pairwise internal networks,
+ private state, private secret scopes, hardening flags, and resource bounds
+ are enforced.
+- Forbidden edges, host exposure, shared volumes, missing faults, and invalid
+ traceability references fail validation.
+- The validator uses only the Go standard library and performs no network or
+ filesystem writes.
+
+### 9.2 Runnable fixture gate, satisfied
+
+- One local scratch image is built and referenced by its OCI manifest digest.
+- PoC-only fixture roles and future online security roles have distinct
+ executable entrypoints.
+- The generated Compose manifest derives from validated `topology.json`.
+- Effective Podman state, not only source YAML, passes 239 runtime checks.
+- Rootless operation, pairwise internal networks, failed host and external
+ probes, no published ports, private volumes, read-only roots, zero process
+ capability sets, and role-token isolation pass.
+- The baseline and all fourteen automatable fault scenarios pass.
+- Reports contain only coarse outcomes. The cover-only row is explicitly not
+ automatable and grants no cover claim.
+
+### 9.3 Protocol-functional gate, not yet satisfied
+
+- Replace fixtures with exact parsers, cryptographic profiles, key ownership,
+ replay persistence, command policy, consensus transitions, and storage
+ receipts from the normative specifications.
+- Pass the PKI and FOG-WIRE functional PoC gates.
+- Add parser conformance, fuzz, race, allocation, load, and mutation tests.
+- Demonstrate current and next epoch transition, rollback refusal, revocation,
+ per-record rekey, fresh handshakes, exact packet geometry, and strict
+ failure behavior.
+
+None of these gates creates an anonymity or production claim.
+
+## 10. Validation Commands
+
+From `deploy/podman/`:
+
+```sh
+gofmt -d cmd/fog-poc-plan/*.go internal/plan/*.go
+go test ./...
+go test -race ./...
+go vet ./...
+go run ./cmd/fog-poc-plan
+go run -buildvcs=false ./cmd/fog-poc-lab -action all -allow-destructive
+```
+
+The expected summary is twelve roles, three mix layers, four stores, nine
+internal pairwise networks, fifteen fault scenarios, and the claim
+`functional-only`.
+
+## 11. Deferred Decisions
+
+This definition does not select:
+
+- a Noise or hybrid post-quantum construction, library, profile ID, port,
+ record size, timer, socket profile, or command shape;
+- a PKI authentication suite, exact epoch schedule, topology shuffle,
+ authority wire-key profile, or recovery ceremony;
+- an active KEMSphinx suite or entry capsule;
+- storage request geometry, durability profile, or receipt primitive;
+- cover, delay, loop, retry, polling, queue, or shutdown distributions;
+- observability fields, aggregation windows, release delays, or thresholds;
+- a production container base image, release channel, deployment user, host
+ firewall, backup, or update mechanism.
+
+These remain explicit dependencies. The fixture generator supplies none of
+them. Any future protocol-functional manifest generator must fail when a
+required value is absent rather than converting fixture values into an
+undocumented protocol default.
+
+## 12. References
+
+- FOG threat model: `FOG-THREAT-MODEL.md`
+- FOG architecture: `FOG-ARCHITECTURE.md`
+- FOG PKI: `FOG-PKI.md`
+- FOG wire protocol: `FOG-WIRE.md`
+- FOG traffic simulator: `FOG-SIMULATION.md`
+- Podman run and network modes:
+ <https://docs.podman.io/en/latest/markdown/podman-run.1.html>
+- Podman internal network option:
+ <https://docs.podman.io/en/v5.8.3/markdown/podman-network-create.1.html>
+- Podman secret management:
+ <https://docs.podman.io/en/stable/markdown/podman-secret.1.html>
diff --git a/docs/FOG-MESSAGING.md b/docs/FOG-MESSAGING.md
new file mode 100644
index 0000000..69b1ffd
--- /dev/null
+++ b/docs/FOG-MESSAGING.md
@@ -0,0 +1,1013 @@
+# FOG Messaging
+
+Status: Draft 0.1
+
+Date: 2026-08-08
+
+## 1. Purpose
+
+This document defines `FOG-MESSAGING`, the Composer-to-Composer messaging
+contract for FOG native asynchronous services.
+
+It fixes the contact model, private vouchers, message-envelope framing,
+authentication boundary, state ownership, atomic send and receive behavior,
+fragmentation, retries, Composer-local deduplication, authenticated commit
+acknowledgments, session renewal, compromise response, and conformance gates.
+
+It also records a non-active cryptographic integration candidate named
+`FOG-MSG-CANDIDATE-PQXDH-TR-MLKEM768-1`. The candidate combines the published
+PQXDH asynchronous handshake with the published Triple Ratchet construction
+and its ML-KEM Braid component. It is an evaluation target, not
+`FOG-MESSAGING-1`, has no numeric profile identifier, is not authorized for a
+public network, and does not by itself establish a deployed security claim.
+
+The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, and MAY describe
+normative requirements in the sense of BCP 14 when they appear in uppercase.
+
+## 2. Scope
+
+`FOG-MESSAGING` owns:
+
+- pairwise contact identities without global usernames;
+- private contact identity cards and single-use receive vouchers;
+- initiation roles and asynchronous session establishment;
+- the fixed message envelope carried inside an encrypted storage record;
+- authenticated application frames and their fixed plaintext layout;
+- message-level state transitions and key lifecycle requirements;
+- Composer-local retry, deduplication, fragment, and acknowledgment state;
+- normal session renewal and identity-change behavior;
+- recovery behavior after compromise or stale backup restore;
+- the common messaging interface used by `fog-drop`, `fog-mailbox`, and
+ `fog-im`;
+- parser limits, failure behavior, and conformance evidence.
+
+This document does not own:
+
+- KEMSphinx packet geometry, routes, SURBs, or packet replay state;
+- mailbox capability derivation, storage record encryption, replication,
+ retention, tombstones, or empty-read behavior;
+- adjacent-link Noise framing;
+- entry capsules, return rendezvous, or transfer bundles;
+- the concrete cover, retry, polling, or delay distributions;
+- local Composer state encryption, update verification, or physical transfer;
+- multi-device synchronization or group messaging.
+
+Those contracts belong to `FOG-SPHINX-PROFILES`, `FOG-STORAGE`, `FOG-WIRE`,
+the entry and rendezvous specifications, the cover profile, `FOG-COMPOSER`,
+`FOG-SX`, and future `FOG-GROUP` work.
+
+## 3. Security Boundary
+
+The sender Composer constructs a messaging envelope before any online role
+receives the work. The intended recipient Composer is the only role allowed to
+authenticate and decrypt that envelope.
+
+The full messaging envelope MUST be the protected plaintext of a fixed-size
+`FOG-STORAGE` record. Its prefix and ratchet header are therefore not visible
+to the blind relay, entry, mixes, courier, or storage replicas. KEMSphinx and
+Noise add independent routing and adjacent-link protections but do not replace
+message-level protection.
+
+FOG-MESSAGING does not hide endpoint compromise, user behavior, screenshots,
+malicious plaintext chosen by a contact, or disclosure by an intended
+recipient. Fixed envelope size also does not hide timing, polling, retries, or
+conversation activity unless the external traffic profile supplies sufficient
+cover and scheduling.
+
+## 4. Protocol Invariants
+
+### MSG-INV-01: No global contact identifier
+
+A contact is represented by a private pairwise identity and local user label.
+The core protocol MUST NOT require a global username, phone number, email
+address, public user directory, or stable network account.
+
+### MSG-INV-02: Contact authentication begins out of band
+
+A voucher cannot authenticate the human or organization that delivered it.
+Before a contact is shown as verified, users MUST compare the complete
+profile-bound fingerprint through an independently authenticated channel.
+
+### MSG-INV-03: One voucher, one initiator, one session
+
+A receive voucher authorizes exactly one designated initiator and exactly one
+initial session. A valid first initialization consumes it. A second different
+initialization using the same voucher is rejected.
+
+### MSG-INV-04: Persist before export or release
+
+The Composer MUST durably commit a send-side ratchet transition and its exact
+immutable envelope before exporting it. It MUST durably commit a receive-side
+ratchet transition and authenticated plaintext before rendering the message or
+exporting an acknowledgment.
+
+### MSG-INV-05: Retry does not advance the ratchet
+
+A retry reuses the exact previously committed end-to-end envelope. It MUST NOT
+derive a second message key or advance the ratchet again. FOG-STORAGE owns the
+immutable box and courier-request generations used to place that envelope.
+Every network retransmission uses new KEMSphinx packet material, route
+randomness, entry material, SURB, rendezvous, and reply material.
+
+### MSG-INV-06: Online roles receive no social identifier
+
+Message IDs, session IDs, fragment IDs, application IDs, acknowledgment state,
+ratchet headers, and contact identities remain inside the encrypted storage
+record. Couriers MAY deduplicate opaque storage requests but MUST NOT receive a
+FOG-MESSAGING identifier.
+
+### MSG-INV-07: Acknowledgment means durable commit
+
+An authenticated message acknowledgment means only that the receiving
+Composer authenticated, decrypted, validated, and durably committed an
+envelope. It MUST NOT mean that a human read, displayed, accepted, or acted on
+the content.
+
+### MSG-INV-08: Fixed external behavior
+
+Drop, mailbox, private-message, chat, data, control, retry, and acknowledgment
+operations use the same consensus-authorized storage and packet classes.
+Application type MUST NOT select external geometry or an immediate response.
+
+### MSG-INV-09: No automatic downgrade
+
+A contact and session use one exact messaging profile. Unknown, retired, or
+incompatible profiles stop processing. A failure MUST NOT activate an older
+handshake, classical-only mode, smaller envelope, direct route, or plaintext.
+
+### MSG-INV-10: Recovery never clones a live ratchet
+
+Copying Composer files, restoring a stale backup, or adding a second device
+MUST NOT create two active copies of one ratchet. Restored conversation state
+enters recovery and requires a new authenticated session.
+
+## 5. Contact Model
+
+### 5.1 Pairwise identity
+
+Each relationship has a unique Composer-generated contact root. Reusing one
+root across unrelated contacts is forbidden because it creates an avoidable
+cross-contact correlation handle.
+
+A pairwise contact identity contains separate public keys for:
+
+- the contact root signature, which binds the contact card, exact profile, and
+ authorized handshake identity;
+- the exact identity key required by the selected asynchronous handshake.
+
+The contact root does not sign ordinary message bodies. Message authenticity
+after session establishment comes from the selected authenticated ratchet.
+FOG does not claim deniability until the complete selected construction and
+its FOG integration have been reviewed for that property.
+
+Human-readable contact names, notes, avatars, and address-book groups are
+Composer-local plaintext. They MUST NOT appear in identity cards, vouchers,
+envelopes, capabilities, logs, or external bundles.
+
+### 5.2 Contact identity card
+
+A `ContactIdentityCard` is a private out-of-band object with these ordered
+semantic fields:
+
+```text
+[
+ object_type,
+ format_version,
+ messaging_profile_offer,
+ pairwise_contact_root_public_key,
+ handshake_identity_public_key,
+ identity_binding,
+ sequence,
+ not_before,
+ not_after,
+ contact_root_signature
+]
+```
+
+`identity_binding` MUST cover the exact handshake identity, primitive suite,
+profile offer, card sequence, validity interval, and a domain separator. The
+card MUST NOT contain a mailbox read capability or global lookup name.
+
+The displayed verification fingerprint MUST commit to the canonical complete
+card, the FOG network identifier, and the proposed messaging profile. The UI
+MUST require a complete comparison or authenticated QR scan, not a short
+user-selected substring.
+
+### 5.3 Receive voucher
+
+A `ReceiveVoucher` is a private single-use capability issued by the contact
+that will answer the initial handshake. Its ordered semantic fields are:
+
+```text
+[
+ object_type,
+ format_version,
+ voucher_id,
+ issuer_identity_card,
+ intended_initiator_root_commitment,
+ messaging_profile_offer,
+ handshake_prekey_bundle,
+ initial_mailbox_write_grant,
+ storage_profile_requirement,
+ sequence,
+ not_before,
+ not_after,
+ flags,
+ issuer_contact_root_signature
+]
+```
+
+The voucher ID MUST contain at least 256 bits from the Composer CSPRNG. The
+root commitment MUST bind the complete intended initiator contact root and the
+voucher domain. A claim-bearing pairwise voucher MUST NOT be bearer-capable.
+
+The prekey bundle MUST contain every one-time classical and post-quantum prekey
+required by the active profile. A claim-bearing FOG profile MUST NOT use a
+last-resort reusable post-quantum prekey. Exhaustion stops new session
+creation until a fresh voucher is exchanged.
+
+`initial_mailbox_write_grant` authorizes deposits only into one dedicated
+pairwise inbound stream. The selected storage construction MAY let its writer
+derive the read capability and tombstone boxes in that same stream, in which
+case the UI and security model MUST state that authority explicitly. The grant
+MUST NOT expose any other inbound or outbound stream, capability registry,
+identity key, recovery key, local database, or storage backup. FOG-STORAGE
+defines its exact construction and rotation.
+
+The issuer MUST atomically persist the voucher record, all corresponding
+private prekeys, the write-grant state, validity, sequence, and consumption
+status before the voucher can leave the Composer. Export failure does not
+permit a second voucher object with the same ID or private prekeys.
+
+### 5.4 Targeted contact ceremony
+
+The initial pairwise ceremony is:
+
+1. Both parties privately exchange `ContactIdentityCard` objects.
+2. They verify the complete profile-bound fingerprints out of band.
+3. They explicitly choose one session initiator.
+4. The responder creates one `ReceiveVoucher` targeted to the chosen
+ initiator root.
+5. The initiator imports and validates the voucher, then prepares one initial
+ session envelope.
+6. That encrypted initial envelope carries a fresh return mailbox write grant
+ for the responder.
+7. The responder consumes the voucher only while atomically committing the
+ valid initial session.
+
+The initiator MUST NOT create a second initial envelope from the same voucher.
+Until the first authenticated response is committed, only the initial content
+envelope may be outstanding. Later user messages remain in a local application
+queue. This bound prevents multiple independent initial sessions and limits
+replay ambiguity.
+
+### 5.5 Bearer and one-way drop vouchers
+
+An explicitly marked bearer voucher provides weaker authentication. The first
+holder able to complete a valid initialization wins. Such a contact MUST be
+displayed as `ACTIVE_UNVERIFIED`, and the UI MUST state that possession of the
+voucher does not identify a person.
+
+`fog-drop` MAY use a separate one-time sealed drop voucher when the receiver
+does not need an authenticated sender or continuing conversation. Each drop
+requires an independent voucher and independent storage grant. A drop profile
+MUST NOT claim ratchet forward secrecy, mutual contact authentication, or
+post-compromise recovery that it does not implement.
+
+## 6. Encoding of Contact Objects
+
+Contact objects use `FOG-MSG-CBOR-1`, a restricted deterministic CBOR profile:
+
+- the top-level and nested structures are arrays with fixed field order;
+- integers are unsigned and use their shortest encoding;
+- byte strings have exact profile-defined lengths;
+- text is forbidden except for a narrowly bounded protocol-owned ASCII label
+ if a later exact profile requires one;
+- maps, floats, tags, indefinite lengths, compression, duplicate fields,
+ unknown fields, and trailing bytes are forbidden;
+- one complete object is at most 65,536 bytes;
+- parsers re-encode a valid object and require byte-for-byte equality.
+
+Signatures cover a domain separator and the canonical array with the signature
+field omitted. The algorithm is selected by the exact messaging profile, not
+by an unauthenticated field supplied to a generic verifier.
+
+Contact objects are confidential social-graph material even though they carry
+public keys. They MUST NOT be published in consensus, a public directory,
+telemetry, logs, crash reports, or ordinary support bundles.
+
+## 7. Messaging Profile Registry
+
+Every active messaging profile is an immutable mapping from one non-zero
+unsigned 32-bit identifier to exact dependencies and behavior. An identifier
+MUST NOT be reused after any byte layout, primitive, limit, state transition,
+or failure rule changes.
+
+An exact profile record includes at least:
+
+```text
+[
+ messaging_profile_id,
+ contact_encoding_id,
+ contact_root_signature_suite_id,
+ handshake_specification_and_revision,
+ handshake_primitive_suite_id,
+ ratchet_specification_and_revision,
+ ratchet_primitive_suite_id,
+ exporter_kdf_id,
+ envelope_format_id,
+ envelope_header_area_length,
+ envelope_ciphertext_area_length,
+ ratchet_aead_id,
+ storage_profile_compatibility_id,
+ maximum_skip,
+ maximum_pending_messages,
+ maximum_fragment_count,
+ maximum_complete_message_length,
+ maximum_concurrent_fragment_groups,
+ retry_profile_id,
+ retention_profile_id,
+ parser_limits_profile_id,
+ conformance_vector_set_id
+]
+```
+
+The accepted FOG consensus authorizes usable profile IDs. Contact cards and
+vouchers narrow that authenticated set but cannot activate an absent profile.
+No party negotiates by trial, and no message advertises alternatives.
+
+An incomplete candidate does not receive a numeric ID. An implementation MUST
+NOT accept a candidate name where an active numeric profile ID is required.
+
+## 8. Fixed Message Envelope
+
+### 8.1 Storage relationship
+
+One `MessageEnvelope` is the fixed-size plaintext of one compatible encrypted
+FOG-STORAGE record. FOG-STORAGE MUST authenticate the entire fixed record,
+including all messaging padding, before exposing it to FOG-MESSAGING.
+
+For a profile with fixed ratchet header area `H` and fixed ratchet ciphertext
+area `C`:
+
+```text
+message_envelope_length = 64 + H + C
+```
+
+Activation requires an explicit compatibility record proving:
+
+```text
+message_envelope_length
+ <= storage_record_plaintext_capacity
+
+storage_operation_length
+ <= compatible KEMSphinx user payload capacity
+```
+
+The current 4,096-byte KEMSphinx candidate user payload is not automatically
+the messaging capacity. FOG-STORAGE still owns request framing, capability
+material, encryption overhead, and replica operation geometry.
+
+### 8.2 Envelope prefix
+
+The exact 64-byte prefix is:
+
+```text
+offset length field
+0 2 envelope_format_version
+2 1 envelope_kind
+3 1 flags
+4 4 messaging_profile_id
+8 8 conversation_generation
+16 32 lookup_id
+48 2 actual_ratchet_header_length
+50 14 reserved
+```
+
+All integers are unsigned network byte order. `flags` and `reserved` are zero
+in the first format. Unknown kinds, non-zero reserved values, invalid profile
+IDs, impossible lengths, and trailing bytes are rejected.
+
+`envelope_kind` is `INIT` or `RATCHET`. For `INIT`, `lookup_id` is the voucher
+ID. For `RATCHET`, it is the session ID. Both remain hidden from online roles
+by FOG-STORAGE encryption.
+
+The INIT handshake transcript MUST authenticate the proposed session ID,
+voucher ID, conversation generation, envelope prefix, complete padded header
+area, both contact identity bindings, and both mailbox write-grant contexts.
+The RATCHET associated data MUST authenticate the prefix and complete padded
+header area.
+
+### 8.3 Header and ciphertext areas
+
+The ratchet header is serialized exactly as required by the active profile and
+right-padded with zero bytes to `H`. Its unpadded size must equal
+`actual_ratchet_header_length`. A parser MUST verify every padding byte after
+successful authentication.
+
+An INIT header MUST carry the exact upstream initialization data and one
+proposed 256-bit session ID generated by the initiator CSPRNG. That session ID
+is unique to the new conversation generation and becomes the `lookup_id` of
+later RATCHET envelopes after the responder authenticates and commits INIT.
+
+The fixed ciphertext area `C` contains one AEAD-protected fixed plaintext
+frame. The active ratchet derives the message key and nonce according to its
+unmodified specification and profile binding. FOG MUST NOT reuse a nonce with
+a key, improvise a second encryption layer with the same key, or expose a raw
+message key to an application module.
+
+The fixed prefix and complete padded header area are associated data. A
+message is not valid until the ratchet authentication, frame parsing, profile,
+generation, sequence, and application-state checks all succeed.
+
+### 8.4 Encrypted plaintext frame
+
+The fixed frame header is exactly 144 bytes:
+
+```text
+length field
+2 frame_version
+1 frame_kind
+1 application_id
+2 flags
+2 reserved
+8 conversation_generation
+8 send_index
+16 message_id
+8 ack_base
+32 ack_bitmap
+16 fragment_group_id
+2 fragment_index
+2 fragment_count
+4 complete_content_length
+2 content_kind
+2 content_length
+32 complete_content_digest
+2 control_code
+2 reserved_2
+N content_and_zero_padding
+```
+
+`N` is fixed by the profile. `content_length` selects the initial content
+bytes; every remaining byte is zero and is checked after AEAD authentication.
+Compression is forbidden.
+
+`frame_kind` is `DATA`, `ACK_ONLY`, or `CONTROL`. `application_id` identifies
+`DROP`, `MAILBOX`, or `IM` only inside the encrypted frame. Unknown values,
+flag bits, controls, or content kinds are critical and cause rejection.
+
+`send_index` begins at 1 for each direction and conversation generation and
+increases without wrap. `message_id` is an independent random 128-bit value
+for one envelope. It is not used by an online role or as a cryptographic key.
+
+Version 1 content kinds are strict UTF-8 text, bounded opaque bytes, and
+protocol control. The renderer MUST NOT interpret HTML, scripts, office
+documents, archives, executable formats, active links, remote resources, or
+embedded previews. Opaque bytes receive a neutral locally generated filename
+and require explicit user action before export.
+
+Typing state, presence, last-seen state, delivery timestamps, read receipts,
+remote avatars, automatic URL fetches, and external MIME resolution are not
+part of the first profile.
+
+## 9. Fragmentation and Reassembly
+
+A semantic message larger than one frame is split by FOG-MESSAGING before
+ratchet encryption. Every fragment is an independent ratchet message with its
+own `send_index`, random `message_id`, message key, fixed envelope, storage
+record, KEMSphinx packet, and outer reply material.
+
+Fragments of one semantic message share:
+
+- one random 128-bit `fragment_group_id`;
+- the exact `fragment_count`;
+- a zero-based `fragment_index`;
+- `complete_content_length`;
+- a profile-selected digest of the complete unfragmented content;
+- the same application and content kind.
+
+The first profile MUST impose limits no larger than:
+
+- 256 fragments per semantic message;
+- 1,048,576 complete content bytes;
+- 16 incomplete fragment groups per contact;
+- one profile-defined total incomplete-byte budget per Composer.
+
+Exact active limits MAY be lower. They MUST be identical for all native
+applications using the profile.
+
+The Composer MUST durably commit all accepted fragments and verify count,
+indexes, length, kind, and complete digest before releasing any part to the
+application. Missing, conflicting, expired, oversized, or invalid groups are
+discarded without partial rendering and without a distinguishable network
+response.
+
+## 10. Session State Machine
+
+### 10.1 Contact and session states
+
+The minimum states are:
+
+- `INVITED`: a validated identity card or unconsumed voucher exists;
+- `INIT_READY`: one initial envelope may be built by the chosen initiator;
+- `INIT_SENT`: the immutable initial envelope is committed and may be retried;
+- `ACTIVE_UNVERIFIED`: the session authenticates a key but no authentic human
+ fingerprint comparison is recorded;
+- `ACTIVE_VERIFIED`: the pairwise identity and session are verified;
+- `RENEWING`: an authenticated transition to a new profile or generation is
+ in progress;
+- `FROZEN_IDENTITY_CHANGE`: an unexpected contact identity change blocks
+ sends and ordinary receives;
+- `RECOVERY_REQUIRED`: restored, inconsistent, rolled-back, or suspected
+ compromised state cannot continue;
+- `CLOSED`: the local relationship is intentionally terminated.
+
+State movement is monotonic except for a reviewed renewal that creates a new
+conversation generation. Reopening `CLOSED`, `FROZEN_IDENTITY_CHANGE`, or
+`RECOVERY_REQUIRED` requires an explicit new contact ceremony or recovery
+protocol, not a file edit or network response.
+
+### 10.2 Initial session
+
+The initiator validates the voucher, active consensus profile, targeted root
+commitment, validity, sequence, prekey signatures, one-time prekey presence,
+and storage compatibility before creating an INIT envelope.
+
+The responder performs all parsing and cryptographic work against staged
+state. A valid INIT must bind the selected voucher, both pairwise identities,
+the proposed random session ID, conversation generation, return mailbox write
+grant, and initial content. Only then may the responder atomically:
+
+1. mark the voucher consumed by the exact initial-envelope digest;
+2. commit the resulting session and receive state;
+3. commit the inbox content and acknowledgment state;
+4. delete the consumed one-time private prekeys;
+5. permit a scheduled authenticated response.
+
+An exact retry maps to the already committed result. A different INIT for a
+consumed voucher is rejected. Failure before the atomic commit leaves the
+voucher usable and does not delete its private prekeys.
+
+### 10.3 Established session
+
+An established session has one sending and one receiving direction per
+conversation generation. The active profile owns the precise ratchet header,
+message-key derivation, skipped-key handling, and post-compromise state.
+
+Application modules never mutate a ratchet directly. They submit bounded
+semantic content to the messaging transaction and receive authenticated
+committed content from it.
+
+## 11. Atomic State Transitions
+
+### 11.1 Send transaction
+
+For each new envelope, the Composer MUST:
+
+1. validate local contact, profile, queue, fragment, and generation bounds;
+2. clone or transactionally stage the current sending ratchet;
+3. derive exactly one message key and construct the exact fixed envelope;
+4. atomically persist the new ratchet state, immutable envelope, send index,
+ application queue transition, retry metadata, and outbox status;
+5. erase the message key and discarded staged state;
+6. only after successful commit, make the envelope eligible for export.
+
+A crash before step 4 produces no exportable envelope. A crash after step 4
+recovers the exact envelope without deriving another message key.
+
+### 11.2 Receive transaction
+
+For each imported storage record, the Composer MUST:
+
+1. authenticate and decrypt the fixed FOG-STORAGE record;
+2. parse the 64-byte prefix and select one local invitation or session;
+3. check the keyed exact-envelope deduplication store;
+4. stage the handshake or ratchet transition without modifying live state;
+5. authenticate, decrypt, and strictly validate the complete frame;
+6. validate generation, sequence, replay window, fragments, application
+ bounds, and acknowledgment summary;
+7. atomically persist new ratchet state, dedup state, inbox or reassembly
+ state, receive window, and peer acknowledgment effects;
+8. erase message, skipped, and discarded staged keys according to the profile;
+9. only after commit, release complete content or schedule an acknowledgment.
+
+Authentication, parsing, policy, resource, or commit failure discards staged
+state and releases no plaintext. The network-facing outcome stays within the
+same coarse storage and cover class.
+
+### 11.3 Local durability requirement
+
+Ratchet state, outbox state, voucher consumption, one-time prekey deletion,
+dedup insertion, and inbox commit form security-critical transactions. A
+profile is not conforming if its storage engine can acknowledge one of these
+effects while losing the others after power failure.
+
+FOG-COMPOSER defines structural encrypted local storage, commit-before-effect,
+and honest rollback-assurance levels. This specification requires transaction
+ordering but does not activate a database or external-anchor profile.
+
+## 12. Retry and Outbox Semantics
+
+The minimum outbox states are:
+
+- `PENDING`: committed and eligible for first export;
+- `EXPORTED`: exported at least once and waiting for authenticated commit ACK;
+- `ACKED`: covered by an authenticated peer acknowledgment;
+- `EXPIRED`: retry age or attempt limit was reached;
+- `CANCELLED`: locally cancelled before export where profile rules permit;
+- `UNCERTAIN`: local import or durability evidence is insufficient and
+ automatic state advancement is unsafe.
+
+An immutable message envelope in `EXPORTED` is never reconstructed.
+FOG-STORAGE atomically creates one immutable box record and one immutable
+courier request generation. Retransmissions within that generation reuse its
+exact storage bytes for courier deduplication, while every transmission uses a
+fresh KEMSphinx packet, SURB, private reply token, route, rendezvous, and entry
+capsule. A later storage request generation may reencrypt the same box only
+under the bounded FOG-STORAGE transition and nonce rules.
+
+The retry profile defines maximum attempts, maximum age, backoff classes,
+jitter source, queue budget, and expiry. It MUST be consensus-authenticated and
+validated by simulation. A real retry MUST wait for its scheduled traffic slot
+and MUST NOT create an immediate application-specific burst.
+
+Expiry means delivery is unknown, not that the peer certainly failed to
+commit. The UI MUST distinguish `ACKED`, `UNACKNOWLEDGED`, and local processing
+failure without claiming network certainty.
+
+## 13. Composer-Local Deduplication
+
+The exact envelope deduplication identifier is stored only inside the
+Composer:
+
+```text
+dedup_id = MAC(K_dedup, profile_domain || HASH(message_envelope))
+```
+
+The active profile defines the exporter that derives `K_dedup`, the hash, MAC,
+domains, and key rotation. The formula is a protocol interface, not permission
+to select arbitrary primitives.
+
+For INIT, the voucher record also binds the first committed envelope digest.
+For RATCHET, the session-local dedup store is checked before attempting a
+ratchet transition. This permits an exact retry to be recognized after its
+message key has been deleted.
+
+Dedup entries persist for at least the maximum retry age plus the profile's
+recovery margin. Count and byte limits are mandatory. Eviction MUST NOT select
+entries based on application type or message content. If safe deduplication
+cannot be guaranteed, the session enters a coarse local error or recovery
+state rather than accepting a conflicting replay.
+
+Message deduplication MUST NOT be delegated to a courier or replica. Their
+separate bounded request replay rules operate on opaque storage operations and
+must not receive `message_id`, `send_index`, or `session_id`.
+
+## 14. Authenticated Commit Acknowledgments
+
+### 14.1 Acknowledgment window
+
+Every encrypted plaintext frame contains one fixed acknowledgment summary for
+the peer-to-local direction:
+
+- `ack_base` is the largest contiguous peer `send_index` durably committed;
+- bitmap bit 0 represents `ack_base + 1`;
+- bitmap bit 255 represents `ack_base + 256`;
+- a set bit means that exact out-of-order index is durably committed.
+
+Indexes at or below `ack_base` are acknowledged. A sender updates its outbox
+only after the summary arrives inside an authenticated, committed ratchet
+message of the expected session and generation.
+
+### 14.2 ACK_ONLY
+
+If no data or control message is due, the Composer MAY create `ACK_ONLY` in a
+normal scheduled message slot. It has the same envelope and external geometry
+as all other frames and advances the ratchet exactly once.
+
+Receiving `ACK_ONLY` MUST NOT by itself trigger an acknowledgment. A later
+ordinary frame may naturally summarize its committed index, but there is no
+immediate ACK-of-ACK exchange. An ACK_ONLY envelope need not remain in an
+ack-wait outbox after its bounded export policy completes.
+
+A duplicate data envelope may cause the next scheduled summary to repeat its
+acknowledgment, but MUST NOT cause an immediate distinguishable reply.
+
+### 14.3 Meaning and fragment behavior
+
+`MESSAGE_COMMIT_ACK` is the only version 1 message delivery acknowledgment. It
+means successful Composer commit. Network acceptance, courier success, replica
+quorum, relay import, display, read state, and user action are different facts
+and MUST NOT be presented as this acknowledgment.
+
+Acknowledging a fragment means that fragment was committed. It does not mean
+the complete semantic message was reassembled or displayed.
+
+## 15. Limits and Malicious Contacts
+
+Every active profile defines exact equal limits for all native applications.
+The first profile MUST NOT exceed:
+
+- `maximum_skip`: 1,024 ratchet message keys;
+- `maximum_pending_messages`: a profile-fixed count and byte budget per
+ contact and Composer;
+- `maximum_fragment_count`: 256;
+- `maximum_complete_message_length`: 1,048,576 bytes;
+- `maximum_concurrent_fragment_groups`: 16 per contact;
+- one 65,536-byte contact object;
+- unsigned 64-bit generations and sequence counters with no wrap.
+
+Skipped message keys are retained only within the exact ratchet bound and are
+securely deleted after use or expiry. The parser validates sizes before
+allocation and performs bounded cryptographic work per imported record.
+
+A malicious contact can send authenticated abusive content and attempt state,
+CPU, storage, fragment, skip-window, or notification exhaustion. FOG therefore
+requires per-contact and global quotas, explicit mute and close controls,
+bounded notifications, no active rendering, and no response amplification.
+Cryptographic authentication is not content safety.
+
+## 16. Session Renewal and Profile Transition
+
+A normal renewal begins only inside an authenticated active ratchet. The old
+session carries a contact-root-signed offer that commits to the exact new
+profile, new conversation generation, fresh one-time initialization material,
+and storage transition context.
+
+Renewal is two-phase:
+
+1. both sides durably commit and authenticate the same transition offer;
+2. both sides confirm the new generation before retiring the old sending
+ state.
+
+Old and new generations have distinct session IDs, ratchet state, dedup keys,
+storage grants, and outboxes. Messages MUST NOT be decrypted under both. There
+is no fallback from a failed new profile to an older one.
+
+An unexpected contact root or handshake identity change is not ordinary
+renewal. The session enters `FROZEN_IDENTITY_CHANGE`, displays both old and new
+profile-bound fingerprints locally, and requires fresh out-of-band
+verification.
+
+## 17. Backup, Restore, and Compromise
+
+### 17.1 Backup boundary
+
+An independently encrypted backup MAY contain pairwise contact roots, verified
+fingerprints, local labels, user-approved history, and metadata needed to
+start recovery. Backup keys remain separate from Composer state-encryption and
+messaging keys.
+
+An initial profile MUST treat active ratchet state, skipped message keys,
+unconsumed one-time prekeys, live vouchers, retry material, and live mailbox
+capabilities as non-resumable after a potentially stale restore. Restored
+conversations enter `RECOVERY_REQUIRED` and cannot send or accept ordinary
+ratchet traffic until a fresh authenticated session is established.
+
+This sacrifices seamless restore to prevent two restored copies from reusing
+message keys, accepting conflicting histories, or impersonating one live
+device state.
+
+### 17.2 Suspected compromise
+
+Post-compromise ratcheting does not defeat an attacker that remains active on
+the Composer, controls randomness, or controls the long-term identity. On
+suspected endpoint or identity compromise, the user MUST replace the affected
+device or image, create new identity material, revoke or abandon old storage
+capabilities where possible, and reauthenticate contacts out of band.
+
+No UI may promise that sending a few more messages automatically removes an
+active attacker.
+
+### 17.3 Multi-device exclusion
+
+The first profile supports one active Composer instance per pairwise identity.
+File copying, shared storage, or concurrent import on two devices is forbidden.
+Multi-device use requires a separate protocol with explicit device identity,
+session convergence, revocation, and metadata analysis.
+
+## 18. Group Messaging Exclusion
+
+Pairwise fan-out is not a group security protocol. It leaks different delivery
+and membership patterns, lacks one coherent group epoch, and does not by
+itself define removal, update, or post-compromise semantics.
+
+Group messaging is deferred to a future `FOG-GROUP` specification. That work
+SHOULD evaluate Messaging Layer Security under RFC 9420 and its architecture
+considerations in RFC 9750, while adapting identity and delivery only through
+explicit FOG trust-boundary analysis. The initial `fog-im` profile is pairwise
+only.
+
+## 19. Candidate Cryptographic Integration
+
+### 19.1 Candidate definition
+
+`FOG-MSG-CANDIDATE-PQXDH-TR-MLKEM768-1` evaluates:
+
+- PQXDH revision 3 for asynchronous initial shared-secret establishment;
+- Double Ratchet specification revision 4 Triple Ratchet integration;
+- ML-KEM Braid specification revision 1 using ML-KEM-768;
+- the exact classical ratchet and authenticated-encryption dependencies
+ required by those maintained specifications;
+- a separate FOG pairwise contact-root signature that binds, but does not
+ replace or weaken, the exact PQXDH identity and prekey checks;
+- FOG fixed framing, atomic storage rules, voucher policy, and outer
+ FOG-STORAGE protection defined in this document.
+
+The candidate requires one-time classical and signed one-time ML-KEM prekeys.
+FOG deliberately excludes the reusable last-resort PQ prekey from a
+claim-bearing profile. Loss of fresh vouchers therefore affects availability.
+
+### 19.2 Claims deliberately withheld
+
+The candidate does not yet establish:
+
+- post-quantum authentication, because the reviewed PQXDH authentication claim
+ still depends on the specified classical authentication assumptions;
+- complete FOG post-quantum security merely from ML-KEM inclusion;
+- deniability;
+- post-compromise recovery under message loss or continued active compromise;
+- safe backup, multi-device, or group behavior;
+- compatibility with the calculated 4,096-byte KEMSphinx payload;
+- implementation or side-channel safety.
+
+### 19.3 Activation gates
+
+Before promotion to an active numeric profile, FOG MUST freeze and verify:
+
+1. exact upstream specification revisions and all primitive identifiers;
+2. one maintained implementation strategy with constant-time and secret
+ deletion review;
+3. byte-exact PQXDH, Triple Ratchet, ML-KEM Braid, FOG envelope, and contact
+ object serialization;
+4. transcript and domain separation, including the outer pairwise root
+ binding;
+5. exact header area, ciphertext area, content capacity, and storage geometry;
+6. loss, reordering, skip-window, retry, crash, restore, and compromise state
+ transitions;
+7. deterministic positive and negative vectors at every boundary;
+8. fuzzing and resource tests for all untrusted inputs;
+9. primitive, integration, side-channel, and lifecycle review;
+10. independent security review before a public security claim.
+
+FOG MUST preserve the upstream constructions rather than silently changing
+their KDF inputs, message-key combination, epoch behavior, or prekey checks.
+Any required departure creates a separately analyzed candidate.
+
+## 20. Key and Secret Lifecycle
+
+| Material | Owner | Persistence | Required destruction or transition |
+| --- | --- | --- | --- |
+| Pairwise contact root private key | one Composer identity | long-term encrypted state; separately encrypted backup MAY be allowed | replace on compromise or explicit identity migration |
+| Handshake identity private key | one Composer pairwise identity | long-term encrypted state | replace with contact root on compromise |
+| Signed classical prekey | voucher issuer Composer | bounded by voucher and profile validity | delete after expiry and all bound voucher states retire |
+| Classical one-time prekey | voucher issuer Composer | persisted before voucher export | delete atomically after valid INIT commit |
+| ML-KEM one-time prekey | voucher issuer Composer | persisted before voucher export | delete atomically after valid INIT commit |
+| Initiator ephemeral handshake secrets | initiator Composer | transaction only | erase after committed initial state and envelope |
+| Handshake shared secrets | both Composers | transaction only | erase after ratchet and exporter state is derived |
+| Classical ratchet private key | one session direction | encrypted mutable session state | erase when the reviewed ratchet transition permits |
+| ML-KEM Braid state | one session | encrypted mutable session state | erase retired epochs and session on close or recovery |
+| Chain key | one session direction | encrypted mutable session state | replace and erase on every chain advance |
+| Message key | one envelope | transaction only | erase after durable send ciphertext or receive commit |
+| Skipped message key | receiving Composer | bounded encrypted state | erase on use, expiry, bound overflow, or session retirement |
+| Session dedup key | one session generation | encrypted mutable state | erase after retry and recovery retention ends |
+| Pairwise inbound stream writer grant | authorized remote contact | deposits, reads where derivable, and tombstones only in that dedicated stream | abandon and replace through FOG-STORAGE rules after compromise or closure |
+| Pairwise inbound stream reader state | receiving Composer; writer MAY derive under selected profile | read, verify, and advance that dedicated stream | never expose access to any other stream or capability registry |
+| Local state-encryption key | Composer profile | protected local state | separate from message, storage, and backup keys |
+| Backup key | user recovery domain | outside backup ciphertext | never derive from a contact or ratchet key |
+
+Secret values, plaintext, capabilities, contact objects, fingerprints,
+session IDs, message IDs, ratchet headers, and envelope digests MUST NOT enter
+logs, metrics, command arguments, crash reports, or support artifacts.
+
+## 21. Failure Behavior
+
+Externally observable failures are coarse and non-amplifying. Online roles do
+not learn whether a storage record held an INIT, data fragment, duplicate,
+ACK_ONLY, invalid ratchet message, or cover object.
+
+The Composer MAY show a local reason such as invalid voucher, verification
+needed, incompatible profile, authentication failure, resource limit, stale
+state, or recovery required. It MUST NOT automatically send an error message
+to an unverified or unauthenticated source.
+
+Unknown-critical fields, malformed UTF-8, invalid padding, overflow, counter
+wrap, conflicting fragment metadata, excessive skips, expired vouchers,
+identity changes, state rollback, and storage commit uncertainty fail closed.
+Failure MUST NOT alter packet size, route length, polling rate, or security
+profile outside the authenticated cover policy.
+
+## 22. Conformance and Test Requirements
+
+Before the local PoC, FOG-MESSAGING requires tests or vectors for:
+
+- canonical contact card and voucher encoding and rejection;
+- profile-bound fingerprint derivation and targeted voucher checks;
+- issue-before-export and consume-once voucher transactions;
+- exact 64-byte prefix and 144-byte frame header;
+- every envelope kind, frame kind, application ID, and content kind;
+- prefix, header-padding, frame-padding, transcript, and generation binding;
+- send crash before commit and after commit;
+- receive crash before commit and after commit;
+- exact retry without a second ratchet advance;
+- immutable storage request retransmission with fresh KEMSphinx, SURB,
+ rendezvous, route, and entry material;
+- exact duplicate, conflicting INIT, replay, old generation, and excessive
+ skip handling;
+- ACK base and bitmap boundaries, reordering, loss, duplicate data, and no
+ ACK-of-ACK trigger;
+- fragment loss, duplication, conflict, timeout, digest failure, and quota
+ exhaustion;
+- malicious contact CPU, memory, disk, notification, and parser bounds;
+- normal renewal, profile transition, identity change, stale restore, and
+ suspected compromise;
+- secure deletion instrumentation where the platform can provide evidence;
+- candidate upstream and FOG integration vectors;
+- absence of prohibited fields in logs, telemetry, storage requests, and
+ external bundles;
+- identical external geometry and scheduling class across native apps,
+ retries, ACKs, and cover operations.
+
+Tests MUST include deterministic positive and negative vectors, property
+tests, fuzzing, transaction fault injection, power-loss simulation, and
+cross-implementation checks before profile activation.
+
+## 23. Threat and Architecture Traceability
+
+| Requirement | Primary controls |
+| --- | --- |
+| `ARC-002` | networkless Composer owns every contact, ratchet, plaintext, and envelope transition |
+| `ARC-004` | message envelope remains independent from KEMSphinx and Noise |
+| `ARC-006` | fixed storage and packet classes hide native application selection from core roles |
+| `ARC-007` | pairwise, ratchet, storage, transport, node, and backup keys have distinct owners and purposes |
+| `ARC-008` | strict object, envelope, queue, fragment, skip, retry, and parser bounds |
+| `ARC-009` | authentication, state, and profile failures stop without bypass or downgrade |
+| `IF-01` | only a committed immutable envelope may enter a Composer export bundle |
+| `IF-02` | imported storage results are untrusted until storage and messaging validation commit |
+| `IF-08` | courier receives only an opaque storage operation, never messaging fields |
+| `IF-09` | storage carries a fixed encrypted record whose plaintext is the message envelope |
+| `TM-NET-02` | directional pairwise stream grants, external schedule, encrypted messaging identifiers, no immediate ACK |
+| `TM-NET-04` | exact-envelope dedup, consume-once voucher, fresh outer retry material |
+| `TM-NET-05` | authenticated ratchet and transcript, strict padding and generation binding |
+| `TM-NET-06` | consensus-authorized immutable profile and application-independent behavior |
+| `TM-ENDPOINT-01` | networkless state owner, transaction ordering, recovery freeze |
+| `TM-ENDPOINT-03` | no live-ratchet backup restore or file-copy multi-device state |
+| `TM-APP-01` | authenticated complete reassembly, bounded content, no active rendering |
+| `TM-OPS-01` | no contact, capability, identifier, digest, payload, or ratchet data in telemetry |
+| `TM-CRYPTO-01` | exact lifecycle table, purpose separation, secure deletion requirements |
+| `TM-CRYPTO-02` | fixed profiles, no trial negotiation, fallback, or candidate activation |
+| `TM-AVAIL-01` | bounded retries, skip windows, fragments, queues, contact objects, and non-amplifying errors |
+
+## 24. Open Dependencies
+
+The structural messaging contract is fixed, but these dependencies remain
+open before an active profile or daemon:
+
+- exact primitive suite, dependency revisions, and maintained implementation
+ for `FOG-MSG-CANDIDATE-PQXDH-TR-MLKEM768-1`;
+- license, API-support, Rust integration, panic, secret-lifecycle, and formal
+ artifact review for the selected messaging implementation path;
+- exact contact-root signature and fingerprint representation;
+- byte-exact candidate serialization and integration vectors;
+- exact fixed `H`, `C`, content capacity, and lower active limits;
+- activation evidence and byte-exact geometry for the structural FOG-STORAGE
+ contract and its non-active BACAP/Pigeonhole candidate;
+- authenticated retry, cover, polling, and expiration distributions;
+- activation evidence for the structural FOG-COMPOSER vault, database,
+ external-anchor, recovery, and update-consumer profiles;
+- identity revocation and fresh-session recovery ceremony;
+- future multi-device and group protocols.
+
+No implementation convenience may silently resolve these dependencies.
+
+## 25. Primary References
+
+- Signal PQXDH specification, revision 3:
+ <https://signal.org/docs/specifications/pqxdh/>
+- Signal Double Ratchet specification, revision 4:
+ <https://signal.org/docs/specifications/doubleratchet/>
+- Signal ML-KEM Braid specification:
+ <https://signal.org/docs/specifications/mlkembraid/>
+- Signal Sesame asynchronous session management specification:
+ <https://signal.org/docs/specifications/sesame/>
+- NIST FIPS 203, Module-Lattice-Based Key-Encapsulation Mechanism Standard:
+ <https://csrc.nist.gov/pubs/fips/203/final>
+- Katzenpost contact voucher specification:
+ <https://katzenpost.network/docs/specs/contactvoucher/>
+- Katzenpost contact voucher narration:
+ <https://katzenpost.network/docs/specs/contact_voucher_narration/>
+- RFC 9420, The Messaging Layer Security Protocol:
+ <https://www.rfc-editor.org/rfc/rfc9420.html>
+- RFC 9750, The Messaging Layer Security Architecture:
+ <https://www.rfc-editor.org/rfc/rfc9750.html>
+- FOG threat model: `FOG-THREAT-MODEL.md`
+- FOG architecture: `FOG-ARCHITECTURE.md`
+- FOG Sphinx profile framework: `FOG-SPHINX-PROFILES.md`
+- FOG storage protocol: `FOG-STORAGE.md`
+- FOG Composer protocol: `FOG-COMPOSER.md`
+- FOG cryptographic suite evaluation: `FOG-CRYPTO-SUITES.md`
+
+These references supply maintained constructions and design lessons. They do
+not make the FOG integration secure by inheritance. FOG still requires exact
+profiles, compatibility calculations, vectors, tests, lifecycle analysis,
+simulation, implementation review, and independent security review.
diff --git a/docs/FOG-OBSERVABILITY.md b/docs/FOG-OBSERVABILITY.md
new file mode 100644
index 0000000..b72034f
--- /dev/null
+++ b/docs/FOG-OBSERVABILITY.md
@@ -0,0 +1,718 @@
+# FOG Observability
+
+Status: Structural Baseline 0.1
+
+Date: 2026-08-08
+
+## 1. Purpose and Claim Boundary
+
+`FOG-OBSERVABILITY-1` defines privacy-safe local logging, operational metric
+collection, aggregate submission, operator diagnosis, and public health
+publication for FOG.
+
+The objective is to detect failed or unsafe role state without creating a
+second traffic-analysis system. Observability is part of the threat model. A
+log server, tracing system, dashboard, crash collector, or support workflow
+can otherwise preserve exactly the timing and relationship metadata that the
+data plane is intended to minimize.
+
+This baseline fixes:
+
+- a no-event-stream production default;
+- a closed metric and local-summary vocabulary;
+- coarse non-overlapping collection windows;
+- bucketed values and low-activity suppression;
+- delayed role-to-observer submissions;
+- separate local, operator, and public views;
+- public anti-differencing requirements;
+- bounded local retention and raw-submission expiry;
+- crash, support, debug, access, and conformance rules.
+
+It does not activate a numeric observability profile. Window duration, bucket
+boundaries, minimum activity, minimum independent reporters, release delay,
+merge policy, retention, serialization, signature suite, and public grouping
+remain explicit evidence-gated selections. No implementation or deployment
+may silently choose them as protocol defaults.
+
+The standard-library Go module in `../observability/` is an executable
+conformance model for the role-local typed collector and bounded volatile
+ring. Its test values are synthetic. It is not `fog-observer`, an IF-11 wire
+codec, a signature implementation, or a public exporter.
+
+## 2. Governing Requirements
+
+This document refines:
+
+- `TM-OPS-01`, logging and metrics leakage;
+- `TM-NET-01`, timing and volume correlation;
+- `TM-NET-03`, active suppression and n-1 behavior;
+- `TM-ROLE-01` through `TM-ROLE-03`, role compromise and collusion;
+- `TM-AVAIL-01`, bounded work and overload handling;
+- `ARC-001`, separate trust domains;
+- `ARC-007`, one owner for private state and keys;
+- `ARC-008`, bounded inputs, work, queues, and state;
+- `ARC-009`, no privacy-weakening recovery;
+- `IF-11`, role-to-observer aggregate submission;
+- the logging sections of `FOG-WIRE`, `FOG-SPHINX-PROFILES`,
+ `FOG-STORAGE`, and `FOG-COMPOSER`.
+
+When this document is narrower than a generic logging or monitoring practice,
+this document controls for claim-bearing FOG profiles.
+
+## 3. Threat Model
+
+The protected assets are:
+
+- whether one user, peer, mailbox, route, packet, or conversation was active;
+- exact event time, direction, sequence, size, and duration;
+- linkability across roles, hosts, epochs, restarts, or support cases;
+- capabilities, keys, tokens, replay state, and opaque protocol objects;
+- operator, host, deployment, and user metadata not already required in
+ authenticated public consensus.
+
+Relevant adversaries include a compromised role, observer, dashboard,
+operator account, support system, backup, or log collector, as well as an
+external party that later obtains retained operational data. A curious or
+compromised observer is within scope. The design therefore does not assume
+that centralizing raw logs is safe.
+
+No observability design can hide what a node operator sees directly on that
+node or what a network observer sees on links. The goal is narrower: do not
+create a new persistent, cross-role, queryable correlation dataset.
+
+## 4. Invariants
+
+### OBS-INV-01: No data-plane event stream
+
+Production roles do not emit one record for each packet, message, handshake,
+storage request, read, write, retry, connection, or cryptographic operation.
+They update bounded in-memory counters or health state inside one coarse
+window.
+
+### OBS-INV-02: Closed typed vocabulary
+
+Every field, role, metric, state, failure class, value kind, and visibility
+class is allowlisted. Production collection APIs accept no arbitrary label
+map, free-form message, raw error, peer-provided string, path, address, or
+identifier.
+
+### OBS-INV-03: Coarse windows only
+
+A role records one window identifier, not event timestamps. Windows are
+profile-fixed, aligned, and non-overlapping. Operators and public consumers
+cannot request arbitrary time ranges.
+
+### OBS-INV-04: No exact exported traffic values
+
+Raw counters exist only inside the open volatile collector. Sealing converts
+them to profile-defined buckets. Exact counts, sizes, latencies, ratios, queue
+depths, and durations do not enter local summaries, observer submissions, or
+publications.
+
+### OBS-INV-05: Suppress small activity sets
+
+Below the profile's minimum activity, every traffic-sensitive metric carries
+the fixed `suppressed` value. Suppression does not remove fields or change the
+report shape. Non-traffic health state may remain available.
+
+### OBS-INV-06: Delayed fixed-schedule submission
+
+Online roles submit on a profile-fixed schedule independent of whether real
+traffic occurred. Each submission declares the earliest release window.
+Immediate event-triggered submission is forbidden.
+
+### OBS-INV-07: Public output requires multiple reporters
+
+No role-local report can become a public report. `fog-observer` first combines
+the profile-required number of independently authenticated reporters, then
+applies coarsening, delay, suppression, and differencing controls.
+
+### OBS-INV-08: No cumulative or subtractable public series
+
+Public output does not expose cumulative counters, overlapping query windows,
+arbitrary filters, node-level series, or stable dimensions that allow two
+answers to isolate a smaller group.
+
+### OBS-INV-09: Bounded retention
+
+Local summaries use a bounded volatile ring or a profile-authorized protected
+store. Raw signed observer submissions expire after bounded processing.
+Retention is fixed in the active profile and cannot be extended through a
+dashboard query or support request.
+
+### OBS-INV-10: Observability is not required for forwarding
+
+Failure, absence, overload, or compromise of `fog-observer` does not alter
+packet forwarding, consensus validity, storage behavior, cover scheduling, or
+cryptographic validation. Roles queue at most a bounded aggregate submission
+and otherwise discard it.
+
+### OBS-INV-11: Production tracing is unavailable
+
+Claim-bearing builds have no packet, record, request, span, or connection
+tracing mode. `DEBUG` or `TRACE` cannot be enabled by runtime configuration.
+Synthetic conformance builds are a separate artifact rejected by production
+configuration.
+
+### OBS-INV-12: Fixed shape within role and profile
+
+Every local summary and observer report contains the same ordered metric
+positions for its role and profile. Unset values are `unknown` or `zero`.
+Sensitive low-activity values are `suppressed`. Presence or field order does
+not reveal which code path ran.
+
+## 5. Information Planes
+
+FOG uses three observability planes:
+
+1. **Local safety summary**: one role retains bounded coarse windows needed
+ for local diagnosis. It never contains event records.
+2. **Operator aggregate**: an online role sends a delayed fixed-shape
+ aggregate over mutually authenticated IF-11. The observer may use it for a
+ protected operator health view.
+3. **Public aggregate**: the observer combines enough independent reporters
+ and publishes only a delayed, coarsened, non-subtractable view.
+
+```text
+role-local raw counters, volatile within one window
+ |
+ | seal once, bucket, suppress
+ v
+ bounded local summary + delayed IF-11 aggregate
+ |
+ | authenticate, combine, expire raw
+ v
+ operator view public view
+ protected delayed and multi-reporter
+```
+
+The networkless Composer and `fog-sx-send`/`fog-sx-receive` do not submit
+automatic observer reports. They may retain only the local safety summary
+allowed by their deployment profile.
+
+## 6. Data Classes
+
+The following classes are forbidden in every FOG log, metric, report,
+dashboard, crash artifact, and generic support bundle:
+
+- plaintext, drafts, rendered content, contacts, labels, fingerprints, and
+ application fields;
+- packet or record bytes, ciphertext samples, entry capsules, KEMSphinx
+ packets, storage envelopes, and imported attacker input;
+- capabilities, vouchers, SURBs, reply material, replay tags, receipt
+ material, ratchets, storage streams, and secret or private key material;
+- message, session, packet, request, record, box, receipt, connection, trace,
+ span, route, or bundle identifiers;
+- source or destination IP address, peer ID, next-hop ID, full route, replica
+ selection, entry set, or per-source history;
+- exact event timestamps, per-operation duration, direction trace, retry
+ sequence, queue item, read frequency, miss streak, and tombstone timing;
+- raw error strings, parser offsets, expected values, detailed cryptographic
+ stages, stack traces, memory dumps, or exception objects;
+- hostname, username, filesystem path, locale, timezone, device serial,
+ billing data, private operator contact, or infrastructure detail absent from
+ the authenticated public consensus.
+
+Hashes, truncation, encryption under a central log key, or pseudonymization do
+not make a forbidden identifier safe. A stable digest remains a correlation
+handle.
+
+## 7. Production Defaults
+
+Before a numeric observability profile is activated, the safe defaults are:
+
+- no packet, request, connection, or storage-access log;
+- no automatic remote logging or telemetry;
+- no public metrics endpoint and no host-published Prometheus endpoint;
+- no OpenTelemetry auto-instrumentation, trace ID, or span ID;
+- no automatic crash upload or support bundle;
+- core dumps, process-memory capture, and production debug mode disabled;
+- bounded volatile local summary only;
+- observer submission and public publication disabled;
+- generic application errors reduced to local fixed failure classes;
+- remote errors remain coarse and non-amplifying under the owning protocol.
+
+A deployment is not permitted to replace these defaults with a generic log
+shipper, service-mesh tracer, application performance monitor, or container
+log collector and still claim the same profile.
+
+## 8. Role-Local Window Model
+
+One role creates exactly one collector for each coarse window. It may update:
+
+- a fixed unsigned counter for an allowlisted count metric;
+- a fixed level bucket for queue, age, latency, ratio, or capacity state;
+- a fixed health value for consensus, clock, key, replay, or cover state;
+- one internal activity counter used only for the suppression decision.
+
+All counters saturate on overflow. They never wrap. The collector holds no
+identifiers, timestamps, strings, samples, exemplars, or per-peer maps.
+
+Sealing is irreversible and happens once. It produces:
+
+- one local report for every role;
+- one delayed observer report only for an online reporting role;
+- no observer report for Composer, observer, or FOG-SX roles.
+
+The role then discards its exact counters. A retry of IF-11 transmits the same
+sealed aggregate object according to the future command-specific retry rule;
+it does not reopen or recount the window.
+
+Discarding collector references is best-effort data minimization. The Go
+runtime, allocator, swap, hibernation, crash capture, and host may retain
+copies, so deployment controls remain necessary and complete erasure is not
+claimed.
+
+## 9. Structural Report Schema
+
+The in-process structural report contains only:
+
+| Field | Meaning | Restriction |
+| --- | --- | --- |
+| `schema_version` | report schema version | fixed to version 1 |
+| `profile_id` | authenticated observability profile | nonzero and consensus-authorized before activation |
+| `scope` | `local` or `observer` | fixed enum |
+| `role` | reporting security role | fixed enum, not node identity |
+| `window_id` | coarse aligned window | no event time |
+| `release_after_window` | earliest observer processing/release boundary | observer scope only and later than source window |
+| `traffic_suppressed` | sensitive metrics are below threshold | fixed boolean, submission schedule remains constant |
+| `measurements` | ordered fixed catalog for role and scope | metric and value enums only |
+
+The JSON emitted by the Go conformance module is a local test and diagnostic
+representation, not the IF-11 wire encoding. Claim-bearing IF-11 requires a
+separate byte-exact bounded encoding and signature specification.
+
+An aggregate-signing key identifier, signature suite, and signature belong to
+the future authenticated IF-11 submission envelope. They are raw observer
+input, never report measurements or public dimensions. Exact signing is not
+defined until the PKI and observability suites select an encoding and
+primitive.
+
+## 10. Value Vocabulary
+
+Count metrics use only:
+
+- `zero`;
+- `low`;
+- `medium`;
+- `high`;
+- `saturated`;
+- `suppressed` when traffic-sensitive activity is below threshold.
+
+Level metrics use only:
+
+- `unknown`;
+- `empty`;
+- `low`;
+- `medium`;
+- `high`;
+- `full`;
+- `suppressed` when traffic-sensitive activity is below threshold.
+
+Health metrics use only:
+
+- `unknown`;
+- `healthy`;
+- `degraded`;
+- `unavailable`.
+
+Bucket boundaries are part of one signed profile. Operators cannot customize
+them per node. Public documentation states the boundaries and their privacy
+rationale after activation.
+
+## 11. Metric Catalog
+
+The structural catalog is intentionally small. `Public eligible` means only
+that a future observer may consider the metric after multi-reporter
+aggregation. It never authorizes direct publication of one report.
+
+| Metric | Kind | Roles | Maximum visibility | Traffic-sensitive |
+| --- | --- | --- | --- | --- |
+| `process_start` | count | all | local | no |
+| `process_stop` | count | all | local | no |
+| `process_restart` | count | all | operator | no |
+| `configuration_rejected` | count | all | operator | no |
+| `consensus_health` | health | online reporters | public eligible | no |
+| `clock_health` | health | online reporters | operator | no |
+| `key_lifecycle_health` | health | online reporters | operator | no |
+| `replay_database_health` | health | mix | operator | no |
+| `queue_occupancy` | level | data plane | operator | yes |
+| `handshake_completed` | count | online reporters | operator | yes |
+| `handshake_failure` | count | online reporters | operator | yes |
+| `connection_age` | level | online reporters | operator | yes |
+| `profile_operations` | count | data plane | operator | yes |
+| `padding_data_ratio` | level | data plane | public eligible | yes |
+| `kemsphinx_failure` | count | mix, courier | operator | yes |
+| `mix_latency` | level | mix | operator | yes |
+| `cover_scheduler_health` | health | data plane | public eligible | no |
+| `storage_success` | count | courier, store | public eligible | yes |
+| `storage_overload` | count | courier, store | public eligible | yes |
+| `storage_expiry` | count | store | public eligible | yes |
+| `storage_corruption` | count | store | public eligible | no |
+| `storage_repair` | count | store | public eligible | no |
+| `capacity` | level | all | operator | no |
+| `composer_boot` | count | Composer | local | no |
+| `composer_lock` | count | Composer | local | no |
+| `composer_integrity_failure` | count | Composer | local | no |
+| `composer_failure` | count | Composer | local | no |
+| `authority_validation_failure` | count | authority | operator | no |
+| `observer_submission_rejected` | count | observer | local | no |
+| `observer_publication_suppressed` | count | observer | local | no |
+
+Adding a metric, role, value, or visibility class is a protocol and threat-
+model change. It requires schema versioning, conformance tests, and
+differencing review. A runtime plugin cannot extend the catalog.
+
+## 12. Failure Classification
+
+Owning protocols map internal errors to the catalog before collection. Raw
+errors never cross the boundary. A coarse count such as
+`configuration_rejected`, `handshake_failure`, `kemsphinx_failure`, or
+`authority_validation_failure` does not encode:
+
+- remote endpoint;
+- exact parser or signature stage;
+- expected or observed bytes;
+- profile candidates;
+- stack, file, line, or subsystem path;
+- retry or connection identity.
+
+Where a protocol needs more than one failure class, it must add a small fixed
+enum to this specification. It cannot place an exception message into a label
+or diagnostic field.
+
+## 13. Window and Time Rules
+
+The active profile defines one origin and one duration. Roles derive:
+
+```text
+window_id = floor((trusted_time - profile_origin) / window_duration)
+```
+
+This calculation is illustrative until the exact time profile is selected.
+No event time is stored. Clock uncertainty beyond the profile bound changes
+`clock_health` and follows the owning protocol's fail-closed time policy.
+It does not cause a role to open shorter windows or emit immediate alerts.
+
+Window duration does not adapt to traffic volume. All reporting roles submit
+at the same declared schedule with bounded profile-defined scheduling
+behavior. Adaptive flush, inactivity flush, and event-triggered window close
+are forbidden.
+
+## 14. Suppression and Bucketing
+
+The profile defines an activity unit for every reporting role, one minimum
+activity threshold, and common bucket boundaries for compatible metric kinds.
+Exact activity is never included in the sealed report.
+
+If activity is below the threshold:
+
+- every traffic-sensitive position is present with `suppressed`;
+- non-traffic health and safety positions retain their bucketed value;
+- the role still emits its scheduled observer submission;
+- the public view emits no small-population inference about that role or
+ window.
+
+The suppression threshold is not an anonymity set size. It is one defense
+against direct low-volume disclosure. Simulation and trace analysis must show
+how it behaves under sparse use, outages, suppression attacks, and colluding
+operators.
+
+## 15. IF-11 Aggregate Submission
+
+IF-11 carries one versioned aggregate submission from one authorized online
+reporting role to `fog-observer`. It uses the mutually authenticated
+role-specific FOG-WIRE context and an aggregate-signing key that is separate
+from Noise, node identity, PKI vote, KEMSphinx, receipt, storage, and release
+keys.
+
+The final IF-11 definition must bind at least:
+
+- network and schema version;
+- observability profile;
+- reporting role and authenticated reporter key;
+- coarse window and earliest release window;
+- exact ordered fixed-shape aggregate body;
+- signature suite and purpose-separated signature.
+
+It must define exact size, padding, authentication, retry, replay, expiry,
+parser limits, and failure behavior. FOG-WIRE fragmentation does not authorize
+variable report geometry or arbitrary metric extensions.
+
+The observer rejects unknown fields, metrics, roles, profiles, values,
+duplicate positions, reordered positions, stale windows, early release,
+unauthorized signers, invalid signatures, and more than one accepted report
+from the same reporter and window. Remote failure remains coarse and
+non-amplifying.
+
+## 16. Observer Processing
+
+`fog-observer` maintains three separate stores:
+
+1. a bounded replay/deduplication index for accepted reporter windows;
+2. short-lived raw signed submissions required for aggregation and audit;
+3. derived operator and public aggregate windows.
+
+The stores use different access rights and retention. Raw submissions expire
+after the bounded processing and dispute interval. They are not copied into a
+general data lake, backup, search index, ticket, or dashboard cache.
+
+The observer never reads role log files, databases, queues, packet captures,
+or container output. It cannot instruct a role to raise verbosity. It has no
+credential accepted by data-plane, storage, authority-voting, or release
+interfaces.
+
+## 17. Operator View
+
+The protected operator view may show only delayed fixed-window buckets from
+metrics whose visibility is `operator` or `public eligible`. It may group by
+role and declared public topology class when the active policy permits.
+
+It does not expose:
+
+- reporter or node drill-down for traffic-sensitive metrics;
+- arbitrary time ranges or window overlap;
+- raw submissions or signature identifiers as chart dimensions;
+- correlation across roles, providers, links, or exact failure times;
+- downloadable event records;
+- queries parameterized by peer, route, connection, packet, or user input.
+
+Access is least privilege. Authentication and authorization failures are
+recorded only as coarse local observer counters. Viewing a dashboard cannot
+extend the underlying retention period.
+
+## 18. Public View and Differencing Defense
+
+A public aggregate requires all of the following:
+
+- the profile-defined minimum number of distinct authorized reporters;
+- the required operator-family and role grouping;
+- completion of the release delay;
+- non-overlapping source and publication windows;
+- bucketed output with no exact totals;
+- suppression for low activity, reporter loss, or unsafe composition;
+- one fixed set of published dimensions;
+- no arbitrary filters, range queries, or node drill-down;
+- review of adjacent releases for differencing and intersection leakage.
+
+Public series are not cumulative. If one group or window is suppressed, the
+observer must not publish another overlapping total from which it can be
+subtracted. A later merge may publish only when the merge rule was fixed in
+advance and every released view remains non-subtractable.
+
+Reporter arrival, rejection, absence, and signature metadata are never public
+dimensions. Public URLs, cache keys, ETags, and response timing must not vary
+by hidden raw reporter state beyond the fixed publication schedule.
+
+## 19. Local Retention and Access
+
+The default implementation keeps sealed local summaries in a bounded volatile
+ring. A role profile may instead authorize protected persistence only when it
+defines:
+
+- exact maximum window count and age;
+- owner and filesystem permissions;
+- encryption and key ownership where required;
+- atomic replacement and crash behavior;
+- deletion and backup exclusion;
+- manual export schema;
+- consequences of a compromised operator account.
+
+No local report is retained indefinitely. Rotation removes the oldest whole
+window. It does not compress old windows into cumulative history.
+
+The Composer stores any permitted summary inside its encrypted vault or
+volatile memory. It has no automatic remote diagnostic path. A manually
+exported Composer diagnostic contains only a newly created coarse report
+selected and previewed by the user, never the raw ring or vault objects.
+
+## 20. Crash and Support Policy
+
+Production profiles disable:
+
+- core dumps and process memory capture;
+- automatic panic, exception, or crash upload;
+- operating-system crash collection that includes role memory;
+- heap, goroutine, thread, profiler, packet, or syscall traces in support
+ artifacts;
+- automatic attachment of logs, configuration, environment, or database
+ files to tickets.
+
+A crash increments only a coarse failure bucket after safe restart when the
+owning state machine permits restart. Security-critical state such as replay,
+ratchet, consensus, storage, or anchor state still follows its own fail-closed
+recovery rules. Observability never authorizes bypass or state recreation.
+
+A manual support artifact uses a separate reviewed schema, shows the exact
+fields to the operator or Composer user before export, excludes raw local
+summaries by default, and has a fixed size and deletion policy.
+
+## 21. Debug and Test Builds
+
+Production artifacts contain no runtime switch that enables prohibited
+logging. Environment variables, signals, command-line flags, configuration
+files, remote administration, or observer requests cannot activate packet or
+event tracing.
+
+Conformance builds may emit verbose traces only when all of the following
+hold:
+
+- the build is distinctly labeled and rejected by production configuration;
+- all keys, packets, contacts, routes, and inputs are public synthetic
+ fixtures generated for the test;
+- the build cannot join a claim-bearing network;
+- traces remain outside release artifacts and support bundles;
+- tests prove that production builds omit the mode.
+
+## 22. Go Conformance Module
+
+`../observability/` follows a small library shape because future role code
+will import the contract, while the observer daemon and wire codec remain
+separate responsibilities.
+
+The module provides:
+
+- fixed `Role`, `Metric`, `Level`, `Health`, `Scope`, and value enums;
+- role and value-kind validation;
+- concurrency-safe saturating in-memory counters;
+- an explicit policy with no default constructor;
+- one-way collector sealing;
+- fixed-shape local and observer reports;
+- low-activity suppression;
+- delayed observer windows;
+- a concurrency-safe bounded volatile local ring;
+- deterministic JSON only for conformance and local diagnostics.
+
+It deliberately does not provide:
+
+- arbitrary labels, messages, attributes, exemplars, or strings;
+- exact timestamps, durations, sizes, counters, or samples in reports;
+- disk persistence or remote log transport;
+- OpenTelemetry, Prometheus, syslog, journald, or service-mesh adapters;
+- IF-11 decoding, signing, networking, observer aggregation, or public output;
+- a numeric production policy.
+
+The absence of those adapters is a security boundary, not an unfinished
+convenience layer.
+
+## 23. Conformance and Adversarial Tests
+
+Before an observability profile becomes claim-bearing, tests must prove:
+
+1. every role rejects every metric outside its catalog;
+2. every metric rejects the wrong value kind and unknown value;
+3. exact counters saturate and never wrap;
+4. sealing occurs once and exact counters are inaccessible afterward;
+5. local and observer shapes are fixed for role and profile across zero, low,
+ threshold, and high activity;
+6. low traffic produces `suppressed`, not a missing field or exact count;
+7. Composer and FOG-SX roles cannot produce observer submissions;
+8. observer reports cannot contain local-only fields;
+9. observer release is later than the source window and overflow fails;
+10. packet, message, trace, peer, route, capability, address, path, error, and
+ timestamp fields are absent from encoded reports;
+11. local retention is bounded and chronological after rotation;
+12. unknown, duplicate, reordered, stale, oversized, and trailing IF-11 input
+ fails before allocation or signature-dependent action;
+13. duplicate reporter windows and replay fail without changing public state;
+14. missing reporters, low populations, adjacent windows, and overlapping
+ queries cannot defeat suppression by differencing;
+15. observer loss cannot alter data-plane or consensus behavior;
+16. production binaries reject debug/test profiles and do not produce core
+ dumps or automatic support uploads;
+17. malformed or attacker-controlled values never reach log formatting;
+18. raw submissions expire and cannot be recovered from backups or dashboard
+ caches after the declared interval.
+
+The current Go module covers items 1 through 11 at the role-local contract
+boundary. IF-11, observer, deployment, and public-release tests remain gated
+on their exact implementations.
+
+## 24. Operational Alerts
+
+Alerts are delayed state conditions, not event notifications. Candidate alert
+classes include:
+
+- consensus `degraded` or `unavailable`;
+- clock `degraded` or `unavailable`;
+- replay database `unavailable`;
+- key lifecycle `degraded` or `unavailable`;
+- cover scheduler `degraded` or `unavailable`;
+- sustained capacity `high` or `full`;
+- sustained storage corruption or repair failure;
+- repeated configuration rejection or process restart buckets.
+
+The exact number of windows needed to alert is profile-defined. Alerts never
+contain a packet, peer, connection, route, request, error string, or event
+time. Immediate local safety shutdown remains the responsibility of the
+owning role and does not wait for an alert.
+
+## 25. Deployment Requirements
+
+A claim-bearing deployment must demonstrate:
+
+- container or service-manager logging cannot capture stdout/stderr event
+ streams from the role;
+- only fixed coarse startup failure output is possible before the collector;
+- core dumps and automatic crash collection are disabled effectively, not
+ only in source configuration;
+- observer credentials cannot access role state or another interface;
+- no host port exposes role metrics directly;
+- local summary storage and observer raw storage meet declared ownership,
+ permissions, capacity, backup, rotation, and deletion rules;
+- dashboard and API caches do not outlive source retention;
+- production configuration rejects unknown metrics, test profiles, and debug
+ modes;
+- clock failure, observer outage, low activity, and reporter loss preserve the
+ declared fail-closed and suppression behavior.
+
+## 26. Requirements Traceability
+
+| Requirement | Observability response |
+| --- | --- |
+| `TM-OPS-01` | closed schema, forbidden data classes, coarse windows, suppression, delayed aggregation, bounded retention |
+| `TM-NET-01` | no fine timing, event stream, route, peer, or cross-role trace identifiers |
+| `TM-NET-03` | cover health, fixed reporting schedule, low-activity suppression, no weakened fallback |
+| `TM-ROLE-01` | role-local collectors and keys, no universal log access |
+| `TM-ROLE-02` | no packet, replay-tag, route, delay, or next-hop records |
+| `TM-ROLE-03` | no request, selection, receipt, storage, or per-source histories |
+| `TM-AVAIL-01` | saturating counters, bounded rings, fixed catalogs, bounded submissions |
+| `ARC-001` | separate role collectors, observer, state, access, and reporting keys |
+| `ARC-007` | one owner for local summaries and aggregate-signing material |
+| `ARC-008` | fixed schema, no dynamic labels, bounded windows and retention |
+| `ARC-009` | observability never authorizes a privacy-weakening recovery path |
+| `IF-11` | delayed authenticated fixed-shape aggregate only |
+
+## 27. Open Activation Decisions
+
+Before enabling IF-11 or public output, FOG must select and validate:
+
+- window origin and duration;
+- activity unit and minimum activity per reporting role;
+- count, level, latency, ratio, age, queue, and capacity bucket boundaries;
+- minimum independent reporters and operator-family diversity per public
+ group;
+- role-to-observer delay, observer-to-public delay, and merge behavior;
+- local, raw observer, derived operator, public, cache, and backup retention;
+- the exact IF-11 body encoding, fixed size, padding, signature suite, key
+ certification, replay, retry, and expiry rules;
+- public dimensions and anti-differencing composition analysis;
+- clock-uncertainty behavior and fixed submission scheduling;
+- deployment-specific storage, access, deletion, and crash controls;
+- simulation and trace evidence for sparse traffic, outages, reporter loss,
+ malicious suppression, collusion, and long-term intersection;
+- independent privacy and implementation review.
+
+Until those decisions are activated through signed profiles and evidence, the
+safe deployment state remains local bounded summaries only, with observer and
+public export disabled.
+
+## 28. References
+
+- FOG threat model: `FOG-THREAT-MODEL.md`
+- FOG architecture: `FOG-ARCHITECTURE.md`
+- FOG adjacent-link protocol: `FOG-WIRE.md`
+- FOG KEMSphinx profiles: `FOG-SPHINX-PROFILES.md`
+- FOG storage: `FOG-STORAGE.md`
+- FOG Composer: `FOG-COMPOSER.md`
+- FOG simulation: `FOG-SIMULATION.md`
diff --git a/docs/FOG-PKI.md b/docs/FOG-PKI.md
new file mode 100644
index 0000000..4bc0ebd
--- /dev/null
+++ b/docs/FOG-PKI.md
@@ -0,0 +1,1814 @@
+# FOG Public Key Infrastructure
+
+Status: Draft 0.1
+
+Date: 2026-08-08
+
+## 1. Purpose
+
+This document defines `FOG-PKI-1`, the normative directory, admission,
+authority, consensus, revocation, topology, and transparency protocol for the
+FOG network.
+
+It refines the following baselines:
+
+- `FOG-THREAT-MODEL.md`, especially `TM-NET-06`, `TM-PKI-01`,
+ `TM-PKI-02`, `TM-PKI-03`, `TM-CRYPTO-01`, `TM-CRYPTO-02`, and
+ `TM-AVAIL-01`;
+- `FOG-ARCHITECTURE.md`, especially `ARC-005`, `ARC-007`, `ARC-008`,
+ `ARC-009`, `IF-03`, `IF-04`, and `IF-05`.
+
+FOG is not implemented. Requirements in this document are protocol targets,
+not statements about deployed security.
+
+The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, and MAY describe
+normative requirements in the sense of BCP 14 when they appear in uppercase.
+
+## 2. Security Goals
+
+FOG-PKI MUST provide:
+
+- one complete authenticated network view for a given epoch;
+- M-of-N authority approval over identical canonical consensus bytes;
+- public attribution of every authority signature;
+- deterministic topology and parameter derivation from public inputs;
+- permissioned admission and public role assignment;
+- purpose-separated current and future node public keys;
+- explicit validity, freshness, grace, and hard-expiry semantics;
+- monotonic state that detects rollback and same-epoch forks;
+- append-only consistency evidence for long-offline Composers;
+- bounded key overlap, rotation, revocation, and authority replacement;
+- public operator-family constraints for route selection;
+- bounded deterministic parsing and offline verification;
+- auditable evidence for authority, node, and checkpoint equivocation.
+
+FOG-PKI does not provide:
+
+- permissionless Sybil resistance;
+- proof that nominally different operators are independent;
+- availability after authority quorum loss;
+- trusted time to an endpoint with no reliable clock;
+- secrecy for public topology or node addresses;
+- safety after compromise of the configured authority threshold;
+- automatic recovery from loss of the pinned authority roots;
+- anonymity by itself.
+
+## 3. Protocol Invariants
+
+### PKI-INV-01: Independent quorum signatures
+
+A valid consensus carries at least M valid signatures from distinct active
+authorities over one identical canonical body. `FOG-PKI-1` does not use one
+shared threshold private key.
+
+### PKI-INV-02: Sign once per epoch
+
+An authority MUST sign at most one consensus body hash for one network and
+epoch. It MUST durably record that body hash before releasing its signature.
+
+### PKI-INV-03: Full view only
+
+Consumers MUST validate a full consensus. They MUST NOT merge descriptors,
+signatures, topology, parameters, or revocations from different consensus
+bodies.
+
+### PKI-INV-04: Monotonic acceptance
+
+A consumer MUST persist the highest accepted authority-set version, consensus
+epoch, consensus hash, and transparency checkpoint. Older or conflicting state
+MUST NOT replace it through an ordinary update.
+
+### PKI-INV-05: Offline roots, online voting keys
+
+Long-term authority root keys certify bounded-lifetime online voting keys.
+Online voting keys sign routine protocol objects. Root private keys MUST NOT be
+present on an online authority service.
+
+### PKI-INV-06: No self-authorized algorithms
+
+The signature and hash suite used to authenticate an object MUST be pinned by
+already trusted state. An object MUST NOT select the algorithm by which its own
+authenticity is decided.
+
+### PKI-INV-07: One node identity, one role
+
+One node identity has exactly one effective online role in an epoch. Layer
+assignment is made by consensus, not self-declared by a node.
+
+### PKI-INV-08: Fail closed at hard expiry
+
+After consensus hard expiry, consumers MUST stop constructing new routes and
+nodes MUST stop accepting new work under that consensus. Only explicitly
+bounded drain and packet-lifetime behavior may continue.
+
+### PKI-INV-09: Public decisions, minimal personal data
+
+Admissions, assignments, suspensions, revocations, authority transitions, and
+equivocation evidence are public. Personal names, private contact details,
+credentials, and sensitive supporting evidence MUST NOT enter public PKI
+objects.
+
+### PKI-INV-10: No trust on first use recovery
+
+Unknown authority, node, operator, mirror, witness, or replacement keys MUST
+NOT become trusted because they are the only reachable keys.
+
+## 4. Roles and Trust
+
+### 4.1 Authority root operator
+
+The root operator controls one authority root key in an offline ceremony. The
+root key certifies that authority's online vote keys and participates in
+authority-set transitions.
+
+### 4.2 Online authority
+
+`fog-authority` accepts descriptors, exchanges protocol messages, constructs
+deterministic proposals, signs one consensus body per epoch, and publishes
+public artifacts. It has no privileged data-plane route.
+
+### 4.3 Operator
+
+An operator controls an operator identity and one or more separately keyed
+nodes. The operator declares common control, infrastructure relationships, and
+role requests. Admission does not prove honesty or independence.
+
+### 4.4 Node
+
+A node signs its descriptor and proves possession of its node identity. It
+publishes only the role-specific public keys and endpoints needed by the
+network.
+
+### 4.5 Mirror
+
+A mirror distributes immutable public objects. It is untrusted for
+authenticity, freshness, completeness, and consistency.
+
+### 4.6 Witness or monitor
+
+A witness independently fetches, compares, archives, and republishes consensus
+and transparency checkpoints. Witnesses improve detection but do not replace
+the authority quorum.
+
+### 4.7 Consumer
+
+Consumers are Composers, blind relays, entries, mixes, couriers, storage
+replicas, services, and observers. Each maintains role-appropriate monotonic
+PKI state. The offline Composer is the final authority for user route
+construction.
+
+## 5. Authority Set and Quorum
+
+An authority set contains:
+
+- an exact authority-set version;
+- an odd number N of authority roots;
+- a quorum M where `floor(N / 2) + 1 <= M <= N`;
+- one stable identifier and root public key per authority;
+- the permitted online signing suites;
+- activation and retirement epochs;
+- the transparency-log identifier;
+- the hash of the previous authority-set manifest.
+
+The initial claim-bearing profile uses N = 3 and M = 2. A later preferred
+profile uses N = 5 and M = 3. A local PoC MAY use a simulated smaller set, but
+the resulting consensus is functional test data only.
+
+Consensus signatures are independent signatures. A signature record names its
+authority and certified online key. A verifier counts at most one valid
+signature per active authority.
+
+Signatures from unknown, duplicate, expired, revoked, not-yet-active, or
+wrong-set keys do not count. Extra invalid signatures MUST make the envelope
+invalid instead of being silently ignored, because inconsistent validation
+would create implementation fingerprints.
+
+## 6. `FOG-PKI-CBOR-1` Encoding
+
+FOG-PKI objects use a restricted deterministic CBOR profile based on RFC 8949.
+This profile is named `FOG-PKI-CBOR-1`.
+
+Every signed object has the form:
+
+```text
+SignedObject = [
+ magic,
+ encoding_version,
+ object_type,
+ body
+]
+```
+
+where:
+
+- `magic` is the byte string `FOGPKI1`;
+- `encoding_version` is unsigned integer `1`;
+- `object_type` is a registered unsigned integer;
+- `body` is an exact-length array defined by this specification.
+
+An authenticated envelope has the form:
+
+```text
+SignedEnvelope = [
+ signed_object_bytes,
+ signatures
+]
+
+SignatureRecord = [
+ authority_or_subject_id,
+ key_id,
+ signature_suite_id,
+ signature_bytes
+]
+```
+
+`signed_object_bytes` is a CBOR byte string containing the exact canonical
+encoding of `SignedObject`. A verifier MUST parse it, enforce this profile,
+re-encode it, and require byte-for-byte equality before checking signatures.
+
+The profile permits only:
+
+- unsigned integers in their shortest encoding;
+- definite-length byte strings;
+- definite-length UTF-8 text strings where a field explicitly permits text;
+- definite-length arrays with exact schema length.
+
+The profile forbids:
+
+- negative integers;
+- maps;
+- floating-point values;
+- tags;
+- simple values, including `null`, `true`, and `false`;
+- indefinite-length items;
+- duplicate set elements;
+- unsorted set-like arrays;
+- trailing bytes or concatenated objects.
+
+Boolean fields use unsigned integer `0` or `1`. Optional fields use an
+explicit variant discriminator and exact variant array, never `null`.
+
+Set-like arrays MUST be sorted by the canonical byte encoding of the complete
+element and MUST contain no duplicate element. Ordered protocol sequences MUST
+retain their specified order and MUST NOT be sorted.
+
+Unknown object types, versions, fields, enum values, key purposes, signature
+suites, hash suites, roles, parameters, or extensions are critical and MUST be
+rejected in version 1.
+
+## 7. Object Types
+
+`FOG-PKI-1` reserves the following object types:
+
+| Value | Object |
+| --- | --- |
+| 1 | `TrustAnchorManifest` |
+| 2 | `AuthorityOnlineKeyCertificate` |
+| 3 | `OperatorRecord` |
+| 4 | `AdmissionDecision` |
+| 5 | `NodeDescriptor` |
+| 6 | `AuthorityCommit` |
+| 7 | `AuthorityReveal` |
+| 8 | `AuthorityProposal` |
+| 9 | `ConsensusBody` |
+| 10 | `RevocationStatement` |
+| 11 | `AuthoritySetTransition` |
+| 12 | `EpochArchive` |
+| 13 | `LogCheckpoint` |
+| 14 | `EquivocationEvidence` |
+| 15 | `RecoveryManifest` |
+| 16 | `ProfileTransition` |
+| 17 | `AuthorityWireKeyCertificate` |
+| 18 | `StorageReplicaManifest` |
+
+Object type assignments never change meaning. Incompatible schemas require a
+new encoding or object version.
+
+## 8. Domain Separation and Identifiers
+
+The trusted PKI suite defines one approved hash construction and its output
+length. All hashes use a distinct ASCII domain string encoded as the first
+element of a canonical CBOR array.
+
+Examples:
+
+```text
+key_id = HASH(["FOG-PKI-KEY-ID-1", algorithm_id, public_key])
+authority_id = HASH(["FOG-PKI-AUTHORITY-ID-1", root_key_id])
+operator_id = HASH(["FOG-PKI-OPERATOR-ID-1", operator_key_id])
+node_id = HASH(["FOG-PKI-NODE-ID-1", node_identity_key_id])
+object_hash = HASH(["FOG-PKI-OBJECT-1", signed_object_bytes])
+consensus_hash = HASH(["FOG-PKI-CONSENSUS-1", consensus_body_bytes])
+descriptor_hash = HASH(["FOG-PKI-DESCRIPTOR-1", descriptor_bytes])
+storage_manifest_hash = HASH([
+ "FOG-PKI-STORAGE-MANIFEST-1",
+ storage_manifest_bytes
+])
+```
+
+Signature input is the canonical encoding of:
+
+```text
+[
+ "FOG-PKI-SIGNATURE-1",
+ network_id,
+ object_type,
+ signature_suite_id,
+ signed_object_bytes
+]
+```
+
+The exact strings above are part of version 1 and are case-sensitive. Binding
+`signature_suite_id` prevents a valid component from being rewrapped under a
+different signature suite over otherwise identical object bytes.
+
+`network_id` is a uniformly random 32-byte value created at genesis and pinned
+in the initial trust-anchor manifest. It is not derived from a DNS name,
+project title, mirror, or operator identity.
+
+Identifiers are public correlation handles inside PKI. They MUST NOT be reused
+as message identities, user accounts, storage capabilities, transport secrets,
+or release identities.
+
+## 9. Absolute Parser Limits
+
+All implementations MUST enforce these absolute version-1 limits before
+allocation proportional to attacker input:
+
+| Item | Limit |
+| --- | --- |
+| Any `SignedEnvelope` | 8 MiB |
+| One `PKIUpdateBundle` | 16 MiB |
+| One `NodeDescriptor` envelope | 128 KiB |
+| One `StorageReplicaManifest` envelope | 1 MiB |
+| One proof bundle | 1 MiB |
+| Nesting depth | 8 arrays |
+| Authorities | 9 |
+| Authority signatures | 9 |
+| Operators | 512 |
+| Nodes in one consensus | 1024 |
+| Endpoints per node | 4 |
+| Family or infrastructure groups per node | 16 |
+| Epoch public keys per node | 24 |
+| Active protocol profiles | 32 |
+| Storage manifests per consensus | 3 |
+| Replica records per storage manifest | 256 |
+| Revocation entries per consensus | 4096 |
+| Text field | 128 UTF-8 bytes |
+| One public key or signature component | 128 KiB |
+
+The initial deployment profile MAY set lower limits. Increasing an absolute
+limit requires a new PKI version and parser review. FOG-PKI uses no compression
+in version 1.
+
+## 10. Trust Bootstrap
+
+### 10.1 Genesis material
+
+A new Composer or node begins with:
+
+- the 32-byte `network_id`;
+- one exact genesis `TrustAnchorManifest` hash;
+- the full genesis manifest;
+- the release-verification trust anchor used for the software image;
+- the initial transparency checkpoint;
+- the accepted PKI encoding and cryptographic suite identifiers.
+
+The genesis manifest is a trust anchor. Self-signatures do not create its
+trust. Its hash MUST be pinned in the verified software release and SHOULD be
+available through at least one independent human-verifiable channel.
+
+DNS, TLS, a mirror, the blind relay, a QR label, or a reachable authority MUST
+NOT replace the pinned genesis hash.
+
+### 10.2 `TrustAnchorManifest`
+
+The manifest body is:
+
+```text
+[
+ network_id,
+ manifest_version,
+ previous_manifest_hash,
+ activation_epoch,
+ retirement_epoch,
+ quorum_m,
+ authority_roots,
+ pki_authentication_suite_id,
+ allowed_object_suite_ids,
+ transparency_log_id,
+ epoch_origin,
+ epoch_duration,
+ schedule_profile_id,
+ hard_limits_profile_id
+]
+```
+
+`authority_roots` is a sorted array of:
+
+```text
+[
+ authority_id,
+ root_key_id,
+ root_signature_algorithm_id,
+ root_public_key,
+ public_alias
+]
+```
+
+`public_alias` is an informational pseudonymous label. It is not an identity
+proof and MUST NOT contain private contact information. It is 1 to 64 bytes
+from ASCII letters, digits, `.`, `_`, and `-`; it need not be globally unique
+and MUST NOT be used in security decisions.
+
+Genesis uses an all-zero `previous_manifest_hash`. Later manifests are
+accepted only through the transition procedure in Section 22.
+
+`manifest_version` is the `authority_set_version` used by certificates,
+consensus, checkpoints, and transitions. The two terms describe the same
+monotonic unsigned integer.
+
+## 11. Authority Key Hierarchy
+
+### 11.1 Authority root key
+
+Each authority has one active offline root identity at a time. Its root private
+key:
+
+- certifies that authority's online voting keys;
+- certifies that authority's dedicated online FOG-WIRE keys;
+- signs authority-set transitions;
+- signs root-key replacement or retirement;
+- participates in authenticated disaster recovery.
+
+It MUST NOT sign routine consensus, descriptor, commit, reveal, proposal,
+checkpoint, or admission objects.
+
+The root private key MUST be generated and used in an offline ceremony. Backup
+material MUST be encrypted, authenticated, geographically separated where
+appropriate, and stored separately from its decryption or recovery secret.
+
+### 11.2 Online vote key
+
+An online voting key signs routine authority protocol objects. It is certified
+by its authority root in an `AuthorityOnlineKeyCertificate`:
+
+```text
+[
+ network_id,
+ authority_set_version,
+ authority_id,
+ online_key_generation,
+ online_key_id,
+ online_signature_suite_id,
+ online_public_key,
+ valid_from_epoch,
+ valid_until_epoch,
+ previous_certificate_hash
+]
+```
+
+The certificate is signed by the matching authority root. An online key
+certificate MUST cover no more than 32 epochs. One current and one next online
+key certificate MAY overlap for at most two epochs.
+
+Consensus validation uses the online key valid for the consensus epoch. A key
+outside its certified interval cannot sign that epoch even if its certificate
+has not been explicitly revoked.
+
+### 11.3 Authority wire key
+
+An authority uses a dedicated online wire key for mutually authenticated
+`FOG-WIRE` links with peer authorities and admitted descriptor submitters. It
+MUST NOT reuse the authority root key or online vote key for transport.
+
+The wire key is certified by the matching authority root in an
+`AuthorityWireKeyCertificate`:
+
+```text
+[
+ network_id,
+ authority_set_version,
+ authority_id,
+ wire_key_generation,
+ wire_key_id,
+ wire_algorithm_id,
+ wire_public_key,
+ supported_wire_profile_ids,
+ valid_from_epoch,
+ valid_until_epoch,
+ previous_certificate_hash
+]
+```
+
+`supported_wire_profile_ids` is sorted and duplicate-free. Every listed
+profile MUST already be trusted and MUST require the declared key algorithm.
+The certificate does not authorize its own algorithm or wire profile.
+
+The certificate is signed by the matching offline authority root. It MUST
+cover no more than 32 epochs. One current and one next authority wire-key
+certificate MAY overlap for at most two epochs. There MUST be exactly one
+valid wire key for one authority, profile, and epoch, unless one already
+trusted profile defines a composite key as one key record.
+
+An authority wire key authenticates only `NODE_AUTHORITY` and
+`AUTHORITY_AUTHORITY` contexts from `FOG-WIRE-1`. It MUST NOT sign votes,
+consensus, checkpoints, admission decisions, descriptors, releases, or user
+objects.
+
+### 11.4 Signature-suite composition
+
+A suite MAY require more than one signature component, including a classical
+and post-quantum component. A composite signature is valid only when every
+mandatory component in the already trusted suite validates over the same
+signature input.
+
+Components from different signature records, objects, keys, or authorities
+MUST NOT be combined to manufacture one valid composite signature.
+
+`FOG-PKI-HASH-CANDIDATE-SHA3-256-1` and
+`FOG-PKI-CANDIDATE-MLDSA65-ED25519-1` are the leading non-active candidates.
+The latter requires independently generated ML-DSA-65 and Ed25519 keys and
+requires both components over the exact suite-bound signature input. Their
+encoding, vectors, separability analysis, implementation, side-channel review,
+and numeric activation remain pre-PoC gates. Algorithm names or post-quantum
+labels alone do not satisfy review.
+
+## 12. Operator Identity and Family Records
+
+An operator uses one dedicated signing identity that is separate from node,
+authority, release, user, and infrastructure login keys.
+
+An `OperatorRecord` contains:
+
+```text
+[
+ network_id,
+ operator_id,
+ operator_key_id,
+ operator_signature_algorithm_id,
+ operator_public_key,
+ public_alias,
+ family_ids,
+ infrastructure_group_ids,
+ declared_provider_codes,
+ declared_as_numbers,
+ declared_country_codes,
+ record_sequence,
+ valid_from_epoch,
+ valid_until_epoch
+]
+```
+
+The operator signs the record, and admission authorities approve its hash.
+
+`family_ids` describe known common control or cooperation across operator
+identities. `infrastructure_group_ids` describe shared provider accounts,
+orchestration, management, backup, monitoring, corporate ownership, or other
+common compromise domains.
+
+Authorities MAY conservatively merge family or infrastructure groups when
+credible evidence indicates common control. They MUST NOT split an existing
+group without an ordinary threshold decision and a public rationale code.
+
+Provider, ASN, and country declarations are public routing inputs, not proof
+of operator independence. Route selection MUST reject reuse of one operator,
+family, or prohibited infrastructure group where the active profile requires
+diversity.
+
+Public records MUST NOT contain legal names, personal email addresses, phone
+numbers, billing identifiers, street addresses, login names, or private abuse
+reports. Authorities MAY maintain a separate access-controlled admission file,
+but its content is outside consensus and MUST NOT be required by clients.
+
+## 13. Permissioned Admission
+
+### 13.1 Application
+
+The initial network is permissioned. An operator applies with:
+
+- its signed `OperatorRecord`;
+- the node identity public key and proof of possession;
+- requested role and capabilities;
+- canonical endpoints;
+- future role-specific public keys;
+- declared family and infrastructure relationships;
+- operational and policy evidence required by governance.
+
+Private supporting evidence is not placed in the public application object.
+
+### 13.2 Decision
+
+An `AdmissionDecision` contains:
+
+```text
+[
+ network_id,
+ decision_sequence,
+ subject_type,
+ subject_id,
+ operator_record_hash,
+ requested_role,
+ disposition,
+ public_reason_code,
+ constraints,
+ effective_epoch,
+ expiry_epoch
+]
+```
+
+`disposition` is one of admit, deny, suspend, reinstate, or retire. It uses a
+registered unsigned integer, not text.
+
+Ordinary admission, role change, reinstatement, and retirement require M
+independent authority signatures. A single authority cannot admit a node.
+
+Admission binds one node identity to one operator and one eligible role. A
+role change requires a new decision. Admission does not assign a mix layer;
+the consensus topology does.
+
+### 13.3 Reapplication and replacement
+
+A revoked node identity MUST NOT be reused. A replacement generates a new node
+identity and follows ordinary admission. A changed endpoint or role-specific
+key does not require a new node identity if a valid monotonic descriptor and
+the existing admission constraints permit the change.
+
+## 14. Node Identity and Descriptor
+
+### 14.1 Node identity
+
+Every online node has one role-local node identity signing key. It signs
+descriptors and proves continuity across epoch-key rotation. It MUST NOT be
+used for Noise transport, KEMSphinx, entry capsules, storage envelopes,
+metrics, release signing, or operator administration.
+
+### 14.2 Descriptor body
+
+A `NodeDescriptor` contains:
+
+```text
+[
+ network_id,
+ descriptor_version,
+ descriptor_sequence,
+ node_id,
+ node_identity_key_id,
+ node_identity_algorithm_id,
+ node_identity_public_key,
+ operator_id,
+ operator_record_hash,
+ admitted_role,
+ capability_ids,
+ endpoints,
+ epoch_public_keys,
+ supported_profile_ids,
+ valid_from_epoch,
+ valid_until_epoch,
+ previous_descriptor_hash
+]
+```
+
+It is signed independently by the node identity and operator identity. Both
+signatures are required.
+
+`descriptor_sequence` starts at zero and increases by exactly one for each
+accepted replacement descriptor. A new descriptor names the previous accepted
+descriptor hash. A gap, rollback, duplicate sequence with a different hash, or
+broken chain is invalid.
+
+One descriptor MUST cover no more than four consecutive epochs. It MUST carry
+the public keys required for its current and next usable key periods without
+extending private-key overlap beyond the owning protocol profile.
+
+### 14.3 Endpoints
+
+An endpoint is:
+
+```text
+[
+ transport_profile_id,
+ address_type,
+ address_bytes,
+ port,
+ priority_class
+]
+```
+
+Only endpoint forms explicitly permitted by the active wire profile are
+valid. An endpoint MUST NOT contain a URL path, username, password, API token,
+query string, fragment, or unauthenticated redirect target.
+
+DNS-only identity is forbidden. If a profile permits DNS discovery, the
+descriptor still binds the node identity and authenticated endpoint behavior;
+DNS never authorizes a different node key.
+
+### 14.4 Epoch public keys
+
+Each public key entry is:
+
+```text
+[
+ purpose_id,
+ algorithm_id,
+ key_id,
+ public_key,
+ valid_from_epoch,
+ valid_until_epoch
+]
+```
+
+Purpose IDs distinguish at least:
+
+- node Noise transport;
+- entry submission capsule;
+- entry return KEMSphinx terminal processing where required;
+- mix KEMSphinx transformation;
+- courier or service terminal KEMSphinx processing;
+- replica envelope protection;
+- replica durable-result receipt authentication;
+- aggregate signing.
+
+A descriptor MUST contain exactly the key purposes required by its admitted
+role and MUST NOT contain keys for another role. The current and next key
+periods MUST be published before the descriptor deadline. More than one active
+key for the same purpose and epoch is invalid unless the active suite defines
+one composite key as a single key record.
+
+Private keys never enter a descriptor, vote, consensus, proof, log, example,
+fixture, or support artifact.
+
+## 15. Epoch and Time Model
+
+The genesis manifest pins:
+
+- `epoch_origin`, an unsigned Unix-time second;
+- `epoch_duration`, a whole number of seconds;
+- one schedule profile;
+- maximum clock uncertainty;
+- consensus freshness and hard-expiry offsets;
+- descriptor, commit, reveal, proposal, signature, and publication deadlines;
+- packet and key grace constraints supplied by the owning protocol profiles.
+
+Epoch number at time `t` is:
+
+```text
+floor((t - epoch_origin) / epoch_duration)
+```
+
+for `t >= epoch_origin`.
+
+The exact initial epoch duration and schedule offsets remain a pre-PoC
+operational selection. They MUST be identical for all participants, encoded in
+the trust manifest, and supported by fault-injection tests. Operators cannot
+override them locally.
+
+Changing epoch origin, duration, schedule, or maximum clock uncertainty
+requires an authority-set manifest transition with at least two epochs of
+advance notice. It is not an ordinary consensus parameter change.
+
+Consumers MUST evaluate time with an explicit local uncertainty interval. A
+relay-provided timestamp, mirror `Date` header, DNS response, or single time
+server is not trusted time. If the uncertainty interval cannot establish
+validity, the consumer fails closed for new work.
+
+## 16. Authority Protocol State Machine
+
+For target epoch E, each online authority executes these phases.
+
+### 16.1 Collect
+
+Authorities collect valid descriptors, operator records, admission decisions,
+revocations, online key certificates, and announced transitions before the
+descriptor deadline.
+
+Inputs arriving after the deadline are considered only for a later epoch.
+Authorities MUST NOT create different inclusion behavior based on requester
+latency after the public deadline.
+
+### 16.2 Commit
+
+Each authority generates a fresh uniformly random secret for epoch E and
+publishes a signed `AuthorityCommit`:
+
+```text
+[
+ network_id,
+ authority_set_version,
+ epoch,
+ authority_id,
+ commitment,
+ previous_consensus_epoch,
+ previous_consensus_hash
+]
+```
+
+The commitment is the suite hash of a domain-separated encoding containing
+the network, epoch, authority, random secret, and previous consensus hash.
+
+Exactly:
+
+```text
+commitment = HASH([
+ "FOG-PKI-COMMIT-1",
+ network_id,
+ authority_set_version,
+ epoch,
+ authority_id,
+ previous_consensus_epoch,
+ previous_consensus_hash,
+ random_secret
+])
+```
+
+### 16.3 Reveal
+
+After the commit deadline, each authority publishes a signed
+`AuthorityReveal` containing the secret corresponding to its prior commitment.
+Reveals without one valid timely commit, invalid reveals, duplicates, or early
+reveals are excluded and recorded.
+
+If fewer than M authorities provide valid commit/reveal pairs, no consensus is
+produced.
+
+The shared seed is derived from the previous consensus hash and the sorted
+valid authority reveals using the pinned hash suite:
+
+```text
+shared_seed = HASH([
+ "FOG-PKI-SHARED-SEED-1",
+ network_id,
+ authority_set_version,
+ epoch,
+ previous_consensus_epoch,
+ previous_consensus_hash,
+ sorted_reveals
+])
+
+sorted_reveals = [
+ [authority_id, random_secret],
+ ...
+]
+```
+
+The complete commit and reveal hashes are included in the consensus audit
+section. `sorted_reveals` is sorted by `authority_id` and contains no duplicate
+authority.
+
+Commit-reveal limits unilateral prediction but permits withholding and denial
+of service by a last revealer. FOG-PKI does not claim bias-free randomness from
+this construction. Topology stability and deterministic public auditing limit
+where the seed is security-critical.
+
+### 16.4 Propose
+
+Each authority independently applies the exact deterministic rules in this
+specification to the same eligible input set. It signs and exchanges an
+`AuthorityProposal` containing the resulting consensus body hash and sorted
+input object hashes.
+
+Authorities MUST NOT average, merge, or majority-vote individual fields from
+different proposals. A body is signable only when at least M authorities have
+published identical proposal body and input hashes.
+
+### 16.5 Sign
+
+Before signing, an authority:
+
+1. validates its active online key certificate;
+2. recomputes the complete canonical consensus body;
+3. verifies the previous consensus and authority-set chain;
+4. persists `(network_id, epoch, consensus_hash)` in durable sign-once state;
+5. refuses if any different hash is already stored for that epoch;
+6. signs the canonical `ConsensusBody` object.
+
+The sign-once record MUST survive restart, restore, and failover. Cloning an
+authority database into two active signers is forbidden.
+
+### 16.6 Publish
+
+Authorities exchange detached signatures. Any publisher can assemble a valid
+`ConsensusEnvelope` only by attaching at least M distinct valid signatures to
+the exact body bytes.
+
+Authorities publish the body, all signature records, relevant certificates,
+input hashes, epoch archive, and transparency material. Mirrors may copy these
+bytes but cannot modify them.
+
+Signature collection closes at the public signature deadline. The final
+sorted signature-record set is committed by the epoch archive before
+`valid_after`. A later signature over the same body remains evidence of that
+authority's statement but MUST NOT be inserted into the finalized consensus
+envelope for that epoch.
+
+## 17. Deterministic Eligibility and Topology
+
+### 17.1 Eligibility filtering
+
+A node is eligible for epoch E only if:
+
+- its admission is active for E;
+- its operator record is active and threshold-approved;
+- its descriptor chain and both descriptor signatures validate;
+- the descriptor covers E and has the required future key material;
+- it is not suspended or revoked;
+- every endpoint, key, capability, and profile is permitted;
+- its role does not conflict with another identity or active assignment;
+- its operator and infrastructure declarations meet the active profile.
+
+All filtering operates on canonical public data and deterministic reason
+codes. Private authority evidence may cause a signed public suspension or
+revocation decision, but it MUST NOT silently change deterministic evaluation.
+
+### 17.2 Effective roles
+
+The consensus assigns each eligible node exactly one of:
+
+- entry;
+- mix layer 1;
+- mix layer 2;
+- mix layer 3;
+- courier;
+- storage replica;
+- declared native service;
+- observer.
+
+The node requests an admitted role. Only mix layer number is assigned by the
+consensus topology algorithm. A node cannot self-place into a layer.
+
+### 17.3 Topology generation
+
+Layer assignment remains stable within one `topology_generation`. A new
+generation is created only for admission, removal, capacity change, diversity
+repair, or deliberate rebalance. Routine epoch key rotation MUST NOT reshuffle
+all mix layers.
+
+For a new generation:
+
+1. eligible nodes are grouped by role;
+2. each group is sorted by `node_id`;
+3. the shared seed drives a suite-defined deterministic pseudorandom shuffle
+ using unbiased sampling;
+4. mix nodes are assigned to three balanced layers;
+5. deterministic constraints maximize operator, family, provider, ASN,
+ country, and infrastructure-group diversity;
+6. a validation pass proves that the profile has at least one allowed complete
+ route and meets its minimum node counts;
+7. failure to satisfy hard constraints makes the proposal invalid.
+
+The exact deterministic shuffle and constraint solver require conformance
+vectors before the PoC. Different implementations MUST produce byte-identical
+topology from the same inputs and seed.
+
+### 17.4 Route constraints
+
+Consensus publishes the attributes needed by the Composer to reject routes
+that repeat one operator, family, or prohibited infrastructure group. The
+consensus MUST NOT precompute one user route or allow operators to choose user
+paths.
+
+## 18. Consensus Body
+
+The canonical `ConsensusBody` is:
+
+```text
+[
+ network_id,
+ pki_version,
+ authority_set_version,
+ epoch,
+ topology_generation,
+ valid_after,
+ fresh_until,
+ valid_until,
+ previous_consensus_epoch,
+ previous_consensus_hash,
+ trust_anchor_manifest_hash,
+ commit_reveal_summary,
+ operator_records,
+ node_descriptors,
+ topology,
+ revocations,
+ storage_manifests,
+ active_profile_ids,
+ network_parameters,
+ announced_transition_hashes
+]
+```
+
+`previous_consensus_epoch` and `previous_consensus_hash` identify the latest
+prior epoch that produced a valid consensus. They may skip scheduled epochs
+that ended without consensus. Each skipped epoch still receives a
+no-consensus transparency archive under Section 24.
+
+### 18.1 Validity times
+
+`valid_after`, `fresh_until`, and `valid_until` are derived exactly from the
+epoch schedule. Authorities do not choose them independently.
+
+- Before `valid_after`, the consensus may be staged but not used for new work.
+- After `fresh_until`, a consumer reports a stale-update condition but MAY
+ continue only until `valid_until` under the same profile.
+- At `valid_until`, new route construction and new work stop.
+
+No mirror, relay, node, operator, or single authority can extend these times.
+
+### 18.2 Full descriptors
+
+Version 1 consensus contains the complete accepted operator records and node
+descriptors needed for route and link validation. It does not use
+state-dependent descriptor deltas or fetch-on-demand partial views.
+
+Each embedded record or descriptor is a CBOR byte string containing its full
+canonical signed envelope. Arrays are sorted by the corresponding stable
+identifier, not by operator alias, endpoint, or arrival order. Consumers
+independently validate the embedded operator and node signatures after the
+authority quorum signature.
+
+`storage_manifests` contains the complete canonical previous, current, and
+announced next `StorageReplicaManifest` objects required by the active
+FOG-STORAGE retention and transition windows. The objects are sorted by
+storage epoch and manifest hash, duplicate-free, and validated under
+`FOG-PKI-CBOR-1` and the authority quorum. Consumers MUST NOT merge replica
+records or storage keys from different manifests. The exact object schema,
+sign-once state, shard inputs, and key windows are defined by
+`FOG-STORAGE.md`.
+
+### 18.3 Profiles and parameters
+
+`active_profile_ids` authorizes exact wire, packet, storage, entry, cover, and
+application protocol profiles. `network_parameters` contains only registered
+integer parameter IDs and bounded unsigned integer values.
+
+For KEMSphinx packet processing, consensus and the applicable
+`FOG-SPHINX-PROFILES` record MUST resolve exactly one packet profile for each
+tuple `(epoch, link_context, packet_class)`. During a transition, old and new
+packet profile IDs may both appear only with an unambiguous activation and
+drain mapping. A consumer MUST reject a consensus that makes profile selection
+ambiguous, requires packet-length detection, or maps one new-work tuple to
+more than one packet profile.
+
+Every node descriptor selected for a KEMSphinx route MUST contain the exact
+epoch KEM key purpose, role, layer, and packet profile required by that route.
+The consensus is invalid if its topology cannot supply a complete four-hop
+forward and reply shape required by the active packet profile.
+
+A parameter cannot select the suite used to authenticate its own consensus.
+Security-critical profile transition requires a preannounced bounded overlap
+and cannot silently downgrade an already accepted minimum.
+
+A `ProfileTransition` contains:
+
+```text
+[
+ network_id,
+ transition_sequence,
+ profile_class,
+ old_profile_ids,
+ new_profile_ids,
+ announcement_epoch,
+ activation_epoch,
+ retirement_epoch,
+ minimum_compatible_version
+]
+```
+
+It requires M independent authority signatures, at least two epochs of advance
+notice, a bounded old/new overlap, and inclusion of its hash in every
+intervening consensus. Parameters classified as profile-bound change only
+through this object. Parameters explicitly classified as dynamic MUST have
+hard minimum, maximum, and per-epoch change bounds in the active profile.
+
+### 18.4 Signature envelope
+
+A `ConsensusEnvelope` is a `SignedEnvelope` whose signed object type is
+`ConsensusBody`. Signature records are sorted by `authority_id` and contain no
+duplicates.
+
+The consensus hash covers the body bytes only. The valid consensus identity is
+the pair `(epoch, consensus_hash)`. Adding a valid signature does not create a
+different consensus identity.
+
+## 19. Consumer Consensus Validation
+
+A consumer MUST perform these checks in order:
+
+1. enforce the outer byte limit before parsing;
+2. decode one exact `SignedEnvelope` and reject trailing data;
+3. validate `FOG-PKI-CBOR-1` and canonical byte equality;
+4. require the pinned `network_id`, PKI version, and object type;
+5. load the already trusted authority-set manifest for the declared version;
+6. validate all required authority online vote-key and wire-key certificates
+ and revocation state;
+7. verify every included signature and require at least M distinct valid
+ active authorities;
+8. recompute the consensus hash;
+9. require exact epoch schedule times and acceptable local clock uncertainty;
+10. reject an epoch below the highest accepted epoch;
+11. reject a different hash for an already accepted epoch;
+12. verify the previous-consensus relationship or the offline consistency
+ bundle described in Section 25;
+13. validate all records, descriptors, key purposes, profile IDs, parameters,
+ revocations, limits, topology assignments, and diversity constraints;
+14. verify the epoch archive and transparency inclusion and consistency
+ evidence;
+15. atomically persist the new manifest version, epoch, consensus hash,
+ checkpoint, and minimum accepted profile state;
+16. only then expose the network view to route or link logic.
+
+Signature verification MUST occur before expensive validation proportional to
+the complete topology where practical, but canonical parsing and strict bounds
+always occur first.
+
+An implementation MUST NOT choose one of two valid-looking same-epoch bodies
+by timestamp, signature count above M, mirror order, lexicographic hash, or
+network reachability. It freezes and reports equivocation.
+
+## 20. Node Consumption and Key Acceptance
+
+Online nodes apply the same consensus authentication rules as Composers and
+also MUST:
+
+- confirm their own effective role and layer before serving traffic;
+- bind peer eligibility to the active consensus and link profile;
+- accept role-specific epoch keys only for their declared purpose;
+- validate root-certified current or staged authority wire keys before
+ `NODE_AUTHORITY` or `AUTHORITY_AUTHORITY` handshakes;
+- stage next-epoch connections without forwarding next-epoch traffic early;
+- close or reject peers removed by the next consensus at the specified
+ boundary;
+- retain previous packet-processing keys only for the exact bounded packet
+ grace period;
+- erase expired epoch private keys after all required replay and packet
+ windows close;
+- stop if local configuration attempts to activate a second role.
+
+An operator configuration cannot add a peer, key, profile, or role absent from
+consensus.
+
+## 21. Revocation and Suspension
+
+### 21.1 Scope
+
+A `RevocationStatement` may target:
+
+- one role-specific epoch key;
+- one node identity and all its keys;
+- one operator and all admitted nodes;
+- one authority online voting key;
+- one authority online wire key;
+- one authority root through an authority-set transition;
+- one protocol profile or suite through a preannounced transition.
+
+### 21.2 Body
+
+```text
+[
+ network_id,
+ revocation_sequence,
+ target_type,
+ target_id,
+ scope,
+ public_reason_code,
+ effective_epoch,
+ effective_time,
+ expiry_epoch,
+ replacement_policy,
+ previous_revocation_hash
+]
+```
+
+Ordinary suspension, revocation, expiry change, and reinstatement require M
+authority signatures.
+
+### 21.3 Self-revocation
+
+A node or operator MAY publish a self-revocation signed by the affected
+identity. Consumers treat a valid self-revocation as an immediate denial-of-
+service-safe removal of that identity. Self-revocation cannot authorize a
+replacement key, identity, operator, role, or authority.
+
+### 21.4 Emergency revocation
+
+Between normal consensuses, M authorities MAY sign one emergency revocation
+envelope. It MUST:
+
+- use a monotonic revocation sequence;
+- identify the last valid consensus hash;
+- have a short explicit expiry no later than the next normal consensus hard
+ expiry;
+- be included in the next epoch archive;
+- never add or reinstate an identity;
+- never change quorum, authority roots, profiles, or topology except by
+ removing the compromised subject.
+
+A single authority warning is public evidence but is not an effective network
+revocation.
+
+### 21.5 Compromise response
+
+After confirmed compromise:
+
+- stop new use of the affected private key;
+- publish self-revocation where safe;
+- issue threshold suspension or revocation;
+- remove affected objects from new consensus;
+- generate purpose-separated replacement keys;
+- use ordinary admission or transition for replacement;
+- preserve public evidence without publishing secret forensic material;
+- document which past and future properties may have failed.
+
+Revocation does not erase previously recorded traffic, signatures, or
+compromise effects.
+
+## 22. Authority-Set Transition
+
+Authority membership, quorum, root keys, PKI authentication suite, epoch
+schedule, and transparency-log identity change only through an
+`AuthoritySetTransition`.
+
+The transition body contains:
+
+```text
+[
+ network_id,
+ old_manifest_version,
+ old_manifest_hash,
+ new_manifest_version,
+ new_manifest_hash,
+ announcement_epoch,
+ activation_epoch,
+ transition_reason_code
+]
+```
+
+Acceptance requires:
+
+1. versions increase by exactly one;
+2. the old manifest is already trusted;
+3. activation is announced at least two epochs in advance;
+4. at least M old authority root signatures validate;
+5. at least the new quorum of new authority root signatures validate;
+6. the transition hash appears in every consensus during the overlap;
+7. the new manifest chains to the old manifest hash;
+8. the consumer persists the new manifest before its activation epoch;
+9. old roots stop authorizing ordinary new state at activation;
+10. a bounded verification overlap exists only for objects created before the
+ boundary.
+
+This dual-quorum procedure follows the principle that both the old trusted set
+and the new set authorize a root transition.
+
+The old quorum signs the exact new root keys and suite identifiers. A new
+authentication suite MUST already be supported and explicitly authorized as a
+transition suite by the old manifest during the overlap. A client MUST NOT
+jump directly from an old suite to an object that can be verified only by an
+algorithm named inside that object. Software support for a suite does not make
+the suite trusted without this chained authorization.
+
+If too many old roots are lost to reach the old quorum, the network has no
+automatic in-protocol recovery. Recovery requires a separately authenticated
+`RecoveryManifest`, explicit user or operator action, and a new trust anchor
+obtained through independent channels. It MUST NOT resemble an ordinary
+update or trust-on-first-use prompt.
+
+## 23. Topology and Profile Revocation Effects
+
+Removing one node MUST NOT cause consumers to bypass its layer. A new
+consensus recomputes a valid complete topology or fails.
+
+If revocation makes the minimum topology or operator diversity impossible:
+
+- no stronger privacy profile is advertised;
+- authorities may publish a lower claim profile only if it was already
+ supported, explicitly authorized, and not a silent downgrade;
+- consumers whose minimum accepted profile is stronger stop new work;
+- the local PoC profile may continue only as functional test mode.
+
+Profile removal is not a generic emergency revocation. It requires a
+preannounced `ProfileTransition`, or an authority-set transition when the PKI
+authentication suite itself changes, unless the profile already has an
+authenticated hard retirement epoch.
+
+## 24. Append-Only Transparency Log
+
+### 24.1 Purpose and limitation
+
+FOG-PKI maintains an append-only Merkle log so a long-offline Composer can
+verify that a new accepted view extends its stored checkpoint with a proof
+whose size grows logarithmically rather than linearly with missed epochs.
+
+The log detects inconsistent signed history when views are compared. It does
+not by itself guarantee that every client sees the same view. Independent
+retrieval, witnesses, and checkpoint gossip remain necessary.
+
+### 24.2 Epoch archive
+
+For every scheduled epoch E, authorities create one canonical `EpochArchive`
+once quorum can finalize either the successful or no-consensus outcome:
+
+```text
+[
+ network_id,
+ epoch,
+ archive_status,
+ failure_reason_code,
+ consensus_hash,
+ authority_manifest_hash,
+ online_key_certificate_hashes,
+ authority_wire_key_certificate_hashes,
+ authority_protocol_object_hashes,
+ consensus_signature_hashes,
+ operator_record_hashes,
+ admission_decision_hashes,
+ node_descriptor_hashes,
+ revocation_hashes,
+ transition_hashes,
+ equivocation_evidence_hashes
+]
+```
+
+All set-like lists are sorted and duplicate-free. The archive commits to the
+public protocol record without embedding private admission evidence.
+
+The archive is a canonical `SignedObject` byte string but needs no individual
+signature envelope. Its authenticity derives from inclusion in the Merkle tree
+identified by an M-of-N signed checkpoint.
+
+For a successful epoch, `archive_status` is unsigned integer `0`,
+`failure_reason_code` is zero, and `consensus_hash` identifies the threshold-
+valid consensus. For an epoch without consensus, `archive_status` is unsigned
+integer `1`, `consensus_hash` is the all-zero hash, and the registered failure
+code records the failed phase without private diagnostics.
+
+`authority_protocol_object_hashes` commits to authority commits, reveals, and
+proposals associated with the epoch.
+`consensus_signature_hashes` commits to every published authority signature
+in the finalized consensus envelope. A consumer requires the envelope's exact
+sorted signature-record hash set to match the archive.
+
+### 24.3 Merkle construction
+
+Each canonical `EpochArchive` byte string is one log leaf in increasing epoch
+order. There is exactly one leaf per scheduled epoch. Missing consensus is
+represented by the canonical failure archive; leaf indices never shift or get
+reused. If quorum loss temporarily prevents checkpointing a failure archive,
+the gap MUST be filled before a later checkpoint can advance past it.
+
+The Merkle tree, leaf hashing, node hashing, inclusion proofs, and consistency
+proofs follow the RFC 9162 append-only construction with FOG-specific domain
+separation and the hash suite pinned by the trust manifest.
+
+The version-1 hashes are:
+
+```text
+empty_hash = HASH(["FOG-PKI-LOG-EMPTY-1", log_id])
+
+leaf_hash = HASH([
+ "FOG-PKI-LOG-LEAF-1",
+ log_id,
+ epoch_archive_bytes
+])
+
+node_hash = HASH([
+ "FOG-PKI-LOG-NODE-1",
+ log_id,
+ left_child_hash,
+ right_child_hash
+])
+```
+
+Tree splitting, inclusion paths, and consistency paths follow RFC 9162. The
+FOG domains above replace the RFC leaf and node prefixes; they do not change
+tree ordering or proof traversal.
+
+The log MUST NOT use commutative child hashing. Left and right position are
+part of verification.
+
+### 24.4 Checkpoint
+
+A `LogCheckpoint` contains:
+
+```text
+[
+ network_id,
+ log_id,
+ authority_set_version,
+ tree_size,
+ root_hash,
+ first_epoch,
+ last_epoch,
+ checkpoint_time
+]
+```
+
+It requires M independent online authority signatures. For a successful
+consensus, its archive and checkpoint MUST be published before that
+consensus's `valid_after`. If quorum cannot checkpoint it by then, consumers do
+not use it for new work. Failure archives are checkpointed before the log can
+advance to any later epoch.
+
+`first_epoch`, `last_epoch`, and `tree_size` MUST describe one contiguous
+epoch sequence with exactly one leaf per scheduled epoch.
+
+### 24.5 Proofs
+
+Mirrors provide:
+
+- an inclusion proof that the target `EpochArchive` is in the new checkpoint;
+- a consistency proof that the new checkpoint extends the consumer's stored
+ checkpoint;
+- the target archive and consensus envelope;
+- any intervening authority-set transitions and online vote-key certificates;
+- authority wire-key certificates required by an online consumer's selected
+ FOG-WIRE contexts.
+
+Proofs are not trusted objects and need no signature. Their validity derives
+from the old stored root and new threshold-signed checkpoint.
+
+### 24.6 Checkpoint comparison
+
+The following are evidence of failure or equivocation:
+
+- two threshold-signed checkpoints with the same `tree_size` and different
+ roots;
+- a newer threshold-signed checkpoint for which no valid consistency proof
+ from an accepted older checkpoint exists;
+- one epoch archive committing to a consensus hash different from the accepted
+ threshold consensus;
+- a checkpoint omitting a promised finalized epoch beyond the publication
+ deadline.
+
+Consumers freeze ordinary PKI updates on verified checkpoint inconsistency.
+They do not reset their stored tree size to make a proof pass.
+
+## 25. Offline Composer Update Bundle
+
+The blind relay or controlled import medium supplies one bounded
+`PKIUpdateBundle` containing:
+
+- the target full consensus envelope;
+- authority online-key certificates needed to verify it;
+- current revocations and emergency revocations;
+- every sequential authority-set transition since the stored manifest;
+- the target epoch archive;
+- a threshold-signed current log checkpoint;
+- an inclusion proof for the target archive;
+- a consistency proof from the Composer's stored checkpoint;
+- independently fetched distinct checkpoints or witness statements where
+ available;
+- a coarse untrusted retrieval timestamp for diagnostics only.
+
+The bundle is a transfer container, not a signed PKI object. Every contained
+object is independently bounded and verified. Extra, duplicate, conflicting,
+or unrelated objects make the bundle invalid.
+
+The Composer MUST:
+
+1. verify transitions sequentially from its stored manifest;
+2. verify the new checkpoint quorum under the correct active authority set;
+3. verify checkpoint consistency from its stored tree root;
+4. verify inclusion of the target epoch archive;
+5. verify the archive's consensus hash;
+6. validate the consensus through Section 19;
+7. compare all supplied distinct checkpoints and evidence;
+8. atomically persist the entire new trusted state;
+9. retain sufficient prior checkpoint and manifest metadata for recovery and
+ equivocation evidence.
+
+If the relay withholds newer data, it can cause freeze or denial of service.
+It cannot make stale data satisfy hard expiry or monotonic checks.
+
+If the Composer lacks its previous checkpoint or manifest state, it MUST NOT
+silently bootstrap from the relay. It requires the explicit recovery process.
+
+## 26. Equivocation Evidence
+
+An `EquivocationEvidence` object contains two or more complete independently
+verifiable signed objects demonstrating one of:
+
+- one authority signs two different consensus hashes for one epoch;
+- two threshold-valid consensus bodies exist for one epoch;
+- one node signs different descriptors with the same sequence and predecessor;
+- one operator signs conflicting records with the same sequence;
+- an authority signs two different storage manifest hashes for one storage
+ epoch;
+- one authority signs incompatible commits, reveals, or proposals;
+- threshold-signed checkpoints conflict or fail append-only consistency;
+- an authority-set transition conflicts at one manifest version.
+
+Evidence objects MUST contain no secret randomness beyond a reveal already due
+for publication and no private governance evidence.
+
+Node or operator equivocation causes deterministic exclusion pending a
+threshold decision. Authority or checkpoint equivocation freezes affected
+consumers until a valid authority-set transition or explicit recovery
+manifest resolves the trust state.
+
+A consumer MUST NOT locally rewrite the authority set merely because it has
+evidence against one authority. That would create a client-specific trust
+view.
+
+## 27. Distribution and Mirrors
+
+Authorities and mirrors publish immutable objects addressed by object hash.
+The latest pointer is an untrusted convenience and MUST return the complete
+bytes needed for verification.
+
+Publishers SHOULD support retrieval by:
+
+- exact consensus epoch and hash;
+- object hash;
+- authority-set manifest version;
+- transparency checkpoint tree size;
+- inclusion and consistency proof parameters;
+- revocation sequence.
+
+HTTP, HTTPS, removable media, QR, FOG-SX-adjacent transfer tooling, or another
+transport MAY carry public PKI objects. Transport security can improve
+availability and privacy but does not create PKI authenticity.
+
+Relays SHOULD fetch from at least two independently operated authorities or
+mirrors and preserve distinct valid responses. They MUST NOT merge them. A
+Composer import bundle includes conflicts as evidence rather than hiding them.
+
+Mirrors MUST NOT receive authority private keys, admission credentials, user
+identities, message traffic, or special consensus signing privilege.
+
+## 28. Failure Behavior
+
+| Condition | Required behavior |
+| --- | --- |
+| Fewer than M valid consensus signatures | reject |
+| Signature from wrong authority set | reject |
+| Any included malformed or invalid signature | reject envelope |
+| Same authority listed twice | reject envelope |
+| Non-canonical encoding | reject before signature acceptance |
+| Unknown-critical value | reject |
+| Wrong network ID | reject |
+| Same epoch, different hash | freeze and retain evidence |
+| Lower epoch or manifest version | reject as rollback |
+| Broken descriptor chain | exclude descriptor; proposal must agree |
+| Missing required future key | exclude node |
+| Invalid topology or insufficient diversity | no consensus for that profile |
+| Commit/reveal quorum failure | no consensus |
+| Proposal body mismatch | do not sign |
+| Consensus past `fresh_until` | report stale; continue only to hard expiry |
+| Consensus past `valid_until` | stop new work |
+| Checkpoint consistency failure | freeze ordinary update |
+| Authority transition lacks dual quorum | reject transition |
+| Lost local monotonic state | require explicit recovery |
+| Clock uncertainty exceeds bound | stop time-sensitive acceptance |
+
+Remote protocol errors MUST be coarse and non-amplifying. Local diagnostics
+MAY identify deterministic validation stages but MUST NOT log private keys,
+private admission material, unpublished random reveals, or credentials.
+
+## 29. Key Lifecycle Table
+
+| Key or secret | Generator | Authorized use | Lifetime and overlap | Compromise response | Backup |
+| --- | --- | --- | --- | --- | --- |
+| Network ID | genesis ceremony | domain and network separation | permanent | new network genesis | public, widely copied |
+| Authority root private key | offline authority ceremony | online-key certificates and set transitions | long-term, one controlled transition overlap | root transition or explicit recovery | encrypted, separate recovery secret |
+| Authority online vote private key | authority root ceremony or controlled online generation | commits, reveals, proposals, consensus, checkpoints | at most 32 epochs, at most 2-epoch overlap | threshold revoke certificate and rotate | SHOULD NOT be restored into concurrent signer |
+| Authority wire private key | authority wire service OS CSPRNG or controlled ceremony | mutually authenticated `FOG-WIRE` authority and descriptor links | root-certified for at most 32 epochs, at most 2-epoch overlap | revoke certificate, stop new sessions, and rotate | SHOULD NOT be restored into concurrent service |
+| Authority randomness secret | online authority CSPRNG | one epoch commit/reveal | one protocol run; erase after reveal and audit window | exclude invalid run; investigate RNG | no backup |
+| Operator identity private key | operator ceremony | operator records and descriptor co-signing | long-term with admitted replacement | suspend operator, replace through admission | encrypted operator-controlled backup |
+| Node identity private key | node enrollment | descriptor continuity | long-term for one node role | self-revoke and new admission | encrypted role-local backup if policy permits |
+| Node epoch private key | owning node CSPRNG | one declared role purpose | current plus bounded grace; future key staged | revoke purpose or node; generate replacement | no routine backup |
+| Replica receipt private key | one storage replica CSPRNG | authenticate one manifest-bounded local durable-result receipt | storage-manifest current plus bounded verification drain | stop receipts, revoke node or purpose, rotate through new manifest | no routine backup |
+| Transparency checkpoint state | every authority | append-only root computation and sign-once tracking | permanent monotonic public history | freeze on inconsistency; recover from audited replicas | authenticated independent authority backups |
+| Consumer monotonic state | each consumer | rollback and consistency detection | lifetime of installation or identity | explicit authenticated recovery | authenticated backup bound to consumer profile |
+
+The networkless Composer refines the final row through the local commitment,
+external-anchor, import, recovery, and update-consumer rules in
+`FOG-COMPOSER.md`. A self-contained consumer backup does not provide complete
+rollback detection.
+
+No private key or randomness secret may appear in consensus, transparency
+logs, test vectors, examples, command lines, environment templates, container
+images, metrics, crash dumps, or support bundles. Tests generate ephemeral
+fixtures at runtime.
+
+## 30. Privacy and Operational Data
+
+Public PKI necessarily reveals:
+
+- node and authority public identities;
+- endpoints and supported transports;
+- effective roles and mix layers;
+- declared operator, family, provider, ASN, country, and infrastructure groups;
+- public key schedules, profiles, validity, admission, suspension, and
+ revocation state;
+- consensus timing and topology changes.
+
+This enables targeting and operational correlation. FOG accepts that exposure
+because clients need a common auditable view and route-diversity inputs.
+
+FOG-PKI MUST NOT publish:
+
+- user or contact identities;
+- mailbox capabilities or packet identifiers;
+- node traffic counts or fine-grained health events;
+- operator legal identity unless voluntarily required by a separate public
+ governance policy;
+- private email, phone, billing, account, or management data;
+- exact physical addresses;
+- unpublished vulnerability or forensic details;
+- authority or node private-key storage design beyond the public assurance
+ profile.
+
+Descriptor uploads, votes, and public objects SHOULD use fixed schedule
+windows and bounded request behavior. Operational metrics belong to the
+aggregate observer interface, not node descriptors.
+
+## 31. Denial-of-Service and Resource Controls
+
+Authorities MUST:
+
+- accept descriptor uploads only for admitted identities;
+- authenticate before expensive signature or policy work where possible;
+- accept at most one selected descriptor chain head per node and epoch;
+- bound connections, body size, signatures, records, keys, endpoints, and
+ pending votes;
+- rate-limit invalid uploads without creating different consensus views;
+- persist protocol phase and sign-once state atomically;
+- use bounded backoff for peer authority exchange;
+- avoid error responses larger than the triggering request;
+- keep publication serving separate from sensitive signing state;
+- remain able to publish existing immutable objects during voting overload.
+
+A malicious admitted node can consume review and descriptor resources. The
+permissioned registry, bounds, expiry, suspension, and operator-wide actions
+limit but do not eliminate this risk.
+
+Authority quorum and transparency do not provide availability against a
+sustained distributed attack or coordinated withholding.
+
+## 32. Conformance and Adversarial Tests
+
+Before the local PoC, FOG-PKI MUST have deterministic fixtures for:
+
+- every object type and exact canonical encoding;
+- re-encoding equality and rejection of alternative CBOR encodings;
+- every registered identifier and domain-separated hash;
+- valid M-of-N consensus for 2-of-3 and 3-of-5 sets;
+- duplicate, unknown, expired, revoked, and wrong-set signatures;
+- composite signature all-component validation;
+- authority online-key certification and overlap boundaries;
+- authority wire-key certification, overlap, profile binding, and rejection of vote-key reuse;
+- descriptor sequence, predecessor, node, and operator signatures;
+- role-specific key-purpose acceptance and cross-purpose rejection;
+- admission, denial, suspension, reinstatement, retirement, and self-revocation;
+- commit, reveal, missing reveal, invalid reveal, and insufficient quorum;
+- byte-identical topology generation from seed and inputs;
+- operator, family, provider, ASN, country, and infrastructure constraints;
+- same-epoch authority and node equivocation;
+- storage-manifest canonical encoding, sign-once persistence, quorum,
+ chaining, previous/current/next windows, receipt keys, and no cross-manifest
+ replica merging;
+- stale, expired, future, rolled-back, frozen, and split consensus;
+- authority sign-once persistence across crash, restore, and failover;
+- ordinary and emergency revocation;
+- dual-quorum authority-set transition;
+- loss of old-root quorum and explicit recovery refusal;
+- RFC 9162 inclusion and consistency proofs, including edge tree sizes;
+- conflicting checkpoints and missing archive leaves;
+- long-offline Composer update from old checkpoint;
+- interrupted atomic state update and recovery;
+- maximum document, array, string, key, signature, and proof limits;
+- parser mutation, fuzz, differential, and allocation tests;
+- clock skew and uncertainty at every boundary;
+- consensus publication and mirror corruption scenarios.
+
+Independent implementations MUST consume the same conformance corpus before
+interoperability is claimed.
+
+## 33. Claim Gates
+
+### 33.1 Functional PoC
+
+The PoC may use simulated authorities but MUST exercise:
+
+- independent signature records;
+- canonical consensus construction;
+- descriptor validation;
+- three-layer topology assignment;
+- current and next node keys;
+- rollback state;
+- revocation;
+- sign-once behavior;
+- transparency inclusion and consistency proofs;
+- expired-consensus fail-closed behavior.
+
+`FOG-LOCAL-POC.md` keeps the authority fixture networkless and explicitly
+non-claim-bearing. Its fault plan requires insufficient-quorum, same-epoch
+fork, stale-consensus, rollback-state, and clock-uncertainty cases before a
+runnable fixture can pass.
+
+### 33.2 Operator alpha
+
+Alpha requires:
+
+- three independently administered authority roots and online services;
+- a 2-of-3 quorum;
+- independent consensus mirrors;
+- at least two independent checkpoint monitors or witnesses;
+- rehearsed online-key compromise, node revocation, authority replacement,
+ quorum loss, clock failure, and restore exercises;
+- public admission, family, revocation, and residual-risk policy;
+- confirmation that no shared provider account or management credential
+ controls the authority quorum.
+
+### 33.3 Production PKI claims
+
+Production claims additionally require:
+
+- independent protocol and implementation review;
+- reviewed concrete classical and post-quantum policy;
+- independently reproduced consensus and transparency roots;
+- published conformance results and unresolved findings;
+- demonstrated long-offline update and recovery ceremonies;
+- ongoing operator-family and common-control auditing;
+- explicit documentation that a compromised authority threshold can still
+ authorize a malicious network view.
+
+## 34. Requirements Traceability
+
+| Requirement | FOG-PKI control |
+| --- | --- |
+| `TM-NET-06` | full canonical consensus, fixed profile IDs, no partial-view merge |
+| `TM-PKI-01` | permissioned admission, operator records, family and infrastructure constraints |
+| `TM-PKI-02` | monotonic epoch and hash state, hard expiry, Merkle inclusion and consistency |
+| `TM-PKI-03` | independent M-of-N authorities, offline roots, bounded online keys, deterministic quorum failure |
+| `TM-OPS-01` | minimal public fields, no user data or private governance evidence |
+| `TM-SUPPLY-01` | pinned genesis, certified online keys, canonical objects, authenticated transitions |
+| `TM-CRYPTO-01` | purpose-specific key hierarchy, bounded overlap, explicit compromise response |
+| `TM-CRYPTO-02` | already-trusted authentication suite, composite all-component validation, no downgrade |
+| `TM-AVAIL-01` | permissioned uploads, strict limits, non-amplification, explicit no-consensus state |
+| `ARC-005` | Composer-validated complete authenticated network view |
+| `ARC-007` | one owner and purpose for root, vote, operator, node, and epoch keys |
+| `ARC-008` | restricted CBOR, exact schema, absolute limits, unknown-critical rejection |
+| `ARC-009` | stale and hard-expiry states, no locally synthesized fallback consensus |
+| `IF-03` | authenticated bounded node descriptor upload |
+| `IF-04` | signed commit, reveal, proposal, signature, and checkpoint exchange |
+| `IF-05` | immutable hash-addressed full consensus and offline update bundle |
+
+## 35. Open Pre-Implementation Selections
+
+The protocol structure is fixed, but these selections block implementation:
+
+- exact encoding, vectors, implementation, artifact-separability analysis,
+ side-channel evidence, and activation record for the non-active SHA3-256
+ and ML-DSA-65 plus Ed25519 candidates;
+- exact epoch duration, schedule offsets, freshness, hard expiry, and clock
+ uncertainty;
+- exact deterministic topology shuffle and diversity constraint algorithm;
+- initial wire, KEMSphinx, entry, storage, cover, and application profile IDs;
+- authority wire-key certificate issuance, storage, revocation, and rollover
+ profile;
+- initial lower operational document and node-count limits;
+- hardware and ceremony profile for authority roots;
+- monitor and witness operators for alpha;
+- explicit `RecoveryManifest` ceremony and user interface;
+- public governance reason-code registry and private evidence retention policy.
+
+These values MUST be selected through reviewed profiles and conformance
+vectors. Implementations MUST NOT invent local defaults.
+
+## 36. References
+
+- FOG threat model: `FOG-THREAT-MODEL.md`
+- FOG architecture: `FOG-ARCHITECTURE.md`
+- FOG wire protocol: `FOG-WIRE.md`
+- FOG storage protocol: `FOG-STORAGE.md`
+- FOG Composer protocol: `FOG-COMPOSER.md`
+- FOG cryptographic suite evaluation: `FOG-CRYPTO-SUITES.md`
+- FOG cryptographic benchmark baseline: `FOG-CRYPTO-BENCHMARKS.md`
+- FOG local Podman PoC: `FOG-LOCAL-POC.md`
+- NIST FIPS 204, Module-Lattice-Based Digital Signature Standard:
+ <https://csrc.nist.gov/pubs/fips/204/final>
+- RFC 9955, Hybrid Signature Spectrums:
+ <https://www.rfc-editor.org/rfc/rfc9955.html>
+- RFC 9980, Post-Quantum Cryptography in OpenPGP:
+ <https://www.rfc-editor.org/rfc/rfc9980.html>
+- Katzenpost public key infrastructure specification:
+ <https://katzenpost.network/docs/specs/pki/>
+- Katzenpost mix network specification:
+ <https://katzenpost.network/docs/specs/mixnet/>
+- Tor directory authority and consensus specifications:
+ <https://spec.torproject.org/dir-spec/>
+- Tor shared-random protocol:
+ <https://spec.torproject.org/srv-spec/>
+- RFC 8949, Concise Binary Object Representation:
+ <https://www.rfc-editor.org/rfc/rfc8949.html>
+- RFC 9162, Certificate Transparency Version 2.0:
+ <https://www.rfc-editor.org/rfc/rfc9162.html>
+- The Update Framework specification:
+ <https://theupdateframework.github.io/specification/>
+
+These references inform quorum operation, offline and online key separation,
+deterministic encoding, append-only consistency proofs, root transitions,
+rollback handling, and freeze detection. They do not make FOG-PKI secure by
+inheritance. FOG requires its own concrete suites, test vectors,
+implementations, operations, and independent review.
diff --git a/docs/FOG-POC-PRESERVATION.md b/docs/FOG-POC-PRESERVATION.md
new file mode 100644
index 0000000..6c045ee
--- /dev/null
+++ b/docs/FOG-POC-PRESERVATION.md
@@ -0,0 +1,152 @@
+# FOG Proof-of-Concept Preservation
+
+Status: Required preservation contract
+
+Date: 2026-08-18
+
+## 1. Objective
+
+The completed local alpha laboratory will be preserved as a reproducible FOG
+proof of concept under the Gab Virebent / Virebent identity. It must remain
+possible to inspect the topology, rebuild the software, start the isolated
+roles, run the demonstration and fault scenarios, verify the results, and
+remove the runtime resources without relying on undocumented local state.
+
+The preserved PoC is functional and educational evidence. It is not an
+anonymity, production, post-quantum, durability, or independent-operator claim.
+
+## 2. Canonical PoC Contents
+
+The source tree must preserve:
+
+- exact source code and pinned Go module dependencies;
+- the pinned compiler and build-tool version requirements;
+- Containerfile and container build context;
+- strict machine-readable topology and fault-scenario definitions;
+- deterministic manifest and configuration generators;
+- test vectors and synthetic non-secret fixtures;
+- commands to build, start, demonstrate, verify, stop, and clean up;
+- tests for role isolation, permitted and forbidden network edges, alternate
+ mix paths, authority quorum, node loss, storage loss, and restoration;
+- a concise demonstration script or command that emits only coarse,
+ non-sensitive outcomes;
+- a sanitized result manifest containing source revision, tool versions,
+ configuration digests, image digest, test outcome, and artifact hashes;
+- dependency and license inventory, plus an SBOM when the selected build tools
+ can produce it reproducibly.
+
+Generated manifests may be retained when they make review easier, but their
+source definition and deterministic generator remain authoritative.
+
+## 3. What Must Not Be Preserved
+
+The PoC repository, release bundle, image, demonstration output, and supporting
+documentation must not contain:
+
+- private keys, passwords, tokens, credentials, recovery material, or real
+ operator secrets;
+- runtime secret volumes, queue state, replay databases, storage contents, or
+ Composer state;
+- real user messages, contacts, capabilities, identifiers, or traffic traces;
+- host login instructions, private addresses, account identifiers, or private
+ operator inventories;
+- container caches, mutable volumes, core dumps, debug logs, or temporary
+ build directories;
+- personal metadata that would link the Virebent identity to unrelated
+ identities or private accounts.
+
+Every demonstration run generates ephemeral role-local fixture secrets from
+the operating-system CSPRNG and destroys the disposable runtime resources at
+cleanup. The saved environment contains only public deterministic inputs and
+sanitized aggregate results.
+
+## 4. Preservation Levels
+
+### 4.1 Source preservation
+
+Source, specifications, generators, lock files, tests, and reproduction
+instructions are the primary long-term artifact. They belong in the future
+FOG repository and a frozen version tag after the Virebent remote and human
+Git author identity are confirmed.
+
+### 4.2 Reproducible build record
+
+The milestone records exact toolchain versions, dependency hashes, build
+arguments, target platform, source revision, binary hashes, and OCI manifest
+digest. A future rebuild must be compared against this record. Differences are
+reported, never silently accepted.
+
+### 4.3 Optional executable archive
+
+At the frozen PoC milestone, one compressed OCI image archive may be attached
+to the release or stored in a Virebent-controlled artifact location. It must
+not be committed to the source repository. The archive is optional because it
+costs storage; the reproducible source is mandatory. Its SHA-256, media type,
+platform, size, and creation command are recorded next to the release.
+
+The archive is created once for the demonstrated platform, not once per
+container or node. All local roles reuse the same digest-pinned multi-binary
+image.
+
+## 5. Demonstration Contract
+
+The preserved PoC must expose one documented, non-interactive top-level
+workflow with these phases:
+
+```text
+preflight -> build once -> create disposable secrets -> start roles
+ -> verify isolation -> run baseline -> run selected faults
+ -> emit sanitized summary -> destroy disposable resources
+```
+
+The workflow must fail closed on missing tools, incompatible versions,
+unexpected existing resources, invalid topology, image-digest mismatch,
+failed containment, incomplete cleanup, or failed tests. It must not download
+or execute an unpinned artifact implicitly.
+
+The default demonstration should finish on one ordinary development host with
+bounded CPU, memory, disk, process, and time budgets. A short baseline mode is
+required. Longer adversarial and benchmark modes remain explicit opt-ins.
+
+## 6. Evidence and Public Presentation
+
+The preserved result states:
+
+- what behavior was demonstrated;
+- exact host and software assumptions;
+- which checks passed, failed, or were skipped;
+- why co-located containers are not independent operators;
+- why the result is not anonymity or production evidence;
+- which protocol components are fixtures rather than active FOG profiles.
+
+Screenshots or video may supplement the machine-readable result but are not
+canonical evidence. Before publication they must be checked for usernames,
+hostnames, paths, terminal history, notifications, embedded metadata, and
+identity leakage.
+
+## 7. Acceptance Gate
+
+The PoC preservation task is complete only when a clean environment can follow
+the documented workflow using the frozen source, reproduce the expected
+sanitized result, and leave no runtime container, network, volume, secret, or
+temporary file behind. The final preservation audit must also confirm that no
+secret or private identity data entered source or release artifacts.
+
+The definition gate is preserved in `deploy/alpha/lab-topology.json`,
+`deploy/alpha/lab-faults.json`, and the dependency-free `internal/lab`
+validator. Its summary is now `runnable: true`: compatible fixtures,
+deterministic Compose generation, all eight baseline routes, 102 containment
+and exact-network checks, all authority single and quorum losses, all six
+single-mix failures, sanitized evidence, and complete disposable-resource
+cleanup were demonstrated by one bounded command on 2026-08-18. It is not yet
+an accepted preserved PoC. A canonical manifest now records dependency,
+external-tool license, source, binary, evidence, and toolchain data with a
+domain-separated artifact-set digest. The project license remains
+`NOASSERTION`, and repository revision metadata plus independent clean-host
+reproduction remain open.
+
+The same-host clean-filesystem rehearsal now reproduces byte-identical fixture
+binaries, complete result, fixed-timestamp OCI image, Compose digest, and
+canonical artifact-set digest. It validates the local ceremony but does not
+satisfy the independent rebuild requirement because the host and installed
+toolchain are shared.
diff --git a/docs/FOG-SECURITY-TEST-PLAN.md b/docs/FOG-SECURITY-TEST-PLAN.md
new file mode 100644
index 0000000..59188b4
--- /dev/null
+++ b/docs/FOG-SECURITY-TEST-PLAN.md
@@ -0,0 +1,120 @@
+# FOG Security Test Plan
+
+Status: Structural test plan
+
+Date: 2026-08-18
+
+## 1. Purpose and Claim Boundary
+
+This plan defines the security test families required before an operator
+alpha. It supplies test contracts, not passing protocol evidence. Existing
+non-cryptographic fixture results may validate the harness but cannot close a
+protocol-functional gate.
+
+Every retained result must identify the software revision, active profile
+digests, test configuration, host class, seed or corpus digest where relevant,
+start and end dates, pass criteria, observed failures, and artifact SHA-256.
+Private keys, capabilities, packet identifiers, user data, and fine-grained
+production traffic do not belong in test reports.
+
+## 2. Test Levels
+
+| Level | Target | Minimum evidence |
+| --- | --- | --- |
+| Unit | pure codecs, state transitions, bounds, profile registry | deterministic tests and mutation cases |
+| Conformance | canonical bytes and public protocol behavior | vectors consumed by two independent implementations |
+| Integration | adjacent roles and complete route | fixed-profile success and fail-closed cases |
+| Fuzz | every untrusted parser and stateful sequence | retained corpus, crash triage, allocation ceilings |
+| Race | daemon concurrency and persistent state | race detector plus restart and contention cases |
+| Fault | process, network, disk, clock, and key failures | deterministic scenario result and restoration check |
+| Load | authenticated and unauthenticated saturation | CPU, memory, queue, latency, and amplification bounds |
+| Side channel | valid and invalid cryptographic paths | reviewed measurement method and statistical result |
+| Simulation | traffic, topology, compromise, suppression | scenario corpus, sensitivity analysis, confidence bounds |
+
+## 3. Mandatory Adversarial Matrix
+
+| Family | Required scenarios | Required invariant |
+| --- | --- | --- |
+| Replay | duplicate packet, restart, replay-state loss, epoch overlap, reply reuse | no repeated semantic effect; unsafe replay state stops processing |
+| Tagging | mutate every authenticated field, packet truncation and extension, SURB mutation | uniform rejection before service effect |
+| n-1 | suppress background traffic, inject hostile traffic, isolate a target, stop cover process | measured isolation signal and explicit degraded or stopped state |
+| Flooding | pre-auth connections, malformed handshakes, fragments, queue pressure, storage fan-out | bounded CPU, memory, connections, disk, and response amplification |
+| Clock | forward and backward jump, excessive uncertainty, cross-authority disagreement | no fresh state outside validity; coarse fault only |
+| Consensus | stale, rollback, freeze, same-epoch fork, malformed mirror, hard expiry | no merge, downgrade, local synthesis, or trust-on-first-use recovery |
+| Authority | one offline, quorum loss, sign-once restart, online-key compromise, replacement | deterministic liveness loss without invalid consensus |
+| Node loss | entry, each mix layer, courier, reconnect storm, replay database corruption | no layer skip, direct fallback, or undeclared route |
+| Storage loss | one replica, quorum loss, stale replica, lost receipt, tombstone conflict | no fabricated durability or resurrection |
+| Network | fragmentation, reordering at application boundaries, partition, asymmetric loss | strict ordered wire state and bounded randomized recovery |
+| State | crash before and after atomic commit, restore old state, disk full, partial write | commit-before-effect and fail-closed recovery |
+| Supply chain | altered binary, dependency change, revoked release, rollback | verification failure or explicit stop, never silent acceptance |
+
+## 4. Parser and Fuzz Targets
+
+Every versioned object parser must have a dedicated target for empty,
+truncated, oversized, non-canonical, duplicate, unknown-critical, trailing,
+deeply nested, maximum-count, and cross-version input. Stateful fuzzers must
+cover handshake, fragmentation, replay, consensus transition, ratchet,
+capability stream, receipt, tombstone, Composer import, recovery, update, and
+FOG-SX reconstruction sequences.
+
+Fuzz harnesses must enforce the protocol's allocation and work limits. A
+result is incomplete when the fuzzer merely avoids panics but permits
+unbounded memory, CPU, disk, file descriptors, goroutines, or cryptographic
+operations.
+
+## 5. Local Alpha Laboratory Matrix
+
+The local laboratory uses three authority fixtures, two mixes per layer, one
+entry, one courier, and four stores. It must exercise both mix choices in
+every layer and cover at least:
+
+1. all eight combinations of one mix per layer;
+2. loss of either mix in each layer while an allowed alternate remains;
+3. loss of both mixes in a layer with no bypass;
+4. one authority offline with quorum preserved;
+5. two authorities offline with no new consensus;
+6. loss of one store and loss of the required receipt quorum;
+7. partitions on every permitted adjacency and probes on every forbidden edge;
+8. restoration that proves stale replay, consensus, and storage state is not
+ silently reused.
+
+These scenarios validate orchestration and protocol behavior only. They do
+not close operator-independence or anonymity gates.
+
+## 6. Pass and Failure Handling
+
+A test family passes only when all declared cases meet byte-exact or bounded
+numeric criteria and every failure has been triaged. Flaky, skipped, timed-out,
+or infrastructure-invalid cases are not passes. Expected failure tests must
+assert the exact permitted coarse outcome and the absence of forbidden side
+effects.
+
+Security regressions retain the smallest non-secret reproducer. Reports use
+aggregate timing and resource data and must not introduce packet-level
+production telemetry. High-severity unresolved findings keep the affected
+readiness gate open.
+
+## 7. Required Commands by Go Module
+
+Each production or conformance Go module must pass:
+
+```sh
+gofmt -d .
+go test ./...
+go test -race ./...
+go vet ./...
+```
+
+Parser modules additionally run their registered fuzz targets under a
+documented time and resource budget. Cryptographic modules run dependency
+verification, complete-operation benchmarks, invalid-input timing tests, and
+independent vector comparison. Container laboratories validate the effective
+runtime state, not only source manifests.
+
+## 8. Gate Mapping
+
+The retained results map directly to `deploy/alpha/readiness.json`. Partial
+fixture evidence remains described in the gate note while status stays
+`open`. A gate changes to `pass` only after its complete scope has immutable
+evidence. The readiness validator does not run tests or trust filenames; it
+checks the declared status and evidence shape so review remains explicit.
diff --git a/docs/FOG-SIMULATION.md b/docs/FOG-SIMULATION.md
new file mode 100644
index 0000000..00fde5e
--- /dev/null
+++ b/docs/FOG-SIMULATION.md
@@ -0,0 +1,321 @@
+# FOG Traffic and Topology Simulation
+
+Status: Engineering Baseline 0.1
+
+Date: 2026-08-08
+
+## 1. Purpose
+
+This document defines the first reproducible simulation boundary for FOG and
+records its initial scenario matrix. It supplies evidence for `TM-NET-01`,
+`TM-NET-02`, `TM-NET-03`, `TM-ROLE-02`, and `TM-AVAIL-01` without promoting a
+delay, cover, topology, entry, or degraded-mode profile.
+
+The implementation is in `../sim/`. The first complete comparison artifact is
+`../sim/results/2026-08-08-baseline.md`.
+
+The simulator is not a daemon, protocol implementation, packet generator,
+deployment controller, capacity benchmark, or anonymity proof.
+
+## 2. Evidence Boundary
+
+The first model answers narrow comparative questions:
+
+- how mean mix delay changes modeled end-to-end latency and local pool overlap;
+- how real and cover traffic density changes bandwidth and observation proxies;
+- how one, two, or three nodes per layer change route diversity and traffic
+ concentration;
+- how independently compromised entry and mix nodes affect repeated target
+ routes;
+- how selective background suppression affects delivery and isolation;
+- how repeated observations shrink a simplified candidate-recipient set.
+
+It does not answer:
+
+- whether FOG is anonymous against a global passive or active observer;
+- which numeric cover or delay profile is safe;
+- whether a local pool metric composes into end-to-end entropy;
+- whether a timing window matches an optimal correlation attack;
+- whether the storage, retrieval, reply, retry, and acknowledgment processes
+ are indistinguishable;
+- whether loop statistics reliably detect n-1 or ordinary failure;
+- how queue capacity, congestion, network jitter, churn, or operator behavior
+ affect deployment.
+
+Every output is tied to the exact model revision, configuration, seed, and
+threat assumptions. A favorable proxy result is never promoted into a public
+privacy claim.
+
+## 3. Model Contract
+
+### 3.1 Reproducibility
+
+`FOG-SIM-DISCRETE-EVENT-1` uses a pinned simulation-only SplitMix64 sequence.
+The same valid configuration and seed produce the same JSON report. The PRNG
+is isolated inside the simulation package and MUST NOT be imported by future
+protocol, cryptographic, route-construction, or daemon code.
+
+Scenario parsing rejects unknown fields, non-regular files, files over 1 MiB,
+non-finite values, invalid probability ranges, invalid topology, and expected
+work above one million packets per replication or five million packets per
+scenario invocation. Runtime generation also aborts if Poisson sampling
+actually reaches either limit, so the validation estimate is not the only
+resource bound.
+
+### 3.2 Traffic
+
+Each simulated user has independent Poisson real and cover injection
+processes. User 0 sends every real target message to user 1 so repeated
+relationship exposure can be measured. Other real and cover recipients are
+uniform among users other than the sender.
+
+This uniform social graph is deliberately simple. It avoids hiding the model
+behind inferred behavioral data, but it is not realistic enough for a claim.
+Future trace-driven and non-uniform models must remain separately named.
+
+### 3.3 Topology and routes
+
+The model contains:
+
+- one configured entry set;
+- exactly three stratified mix layers;
+- one to three configured mixes per layer in the initial scenarios;
+- four KEMSphinx positions, with the terminal outside the three delay pools;
+- five core link transmissions for a fully delivered forward packet;
+- one 16,150-byte packet on every link.
+
+Nodes receive deterministic operator-family assignments. The route generator
+enumerates only entry, L1, L2, and L3 combinations with four distinct declared
+operator families. A session uses a small entry set for a configured number of
+packets before rotation. It does not rotate entry on every message.
+
+The model does not yet include terminal operator diversity, provider, ASN,
+country, infrastructure-group, capacity, or topology-generation constraints.
+It therefore validates only the narrow declared-family rule.
+
+### 3.4 Delay and fixed costs
+
+Each sender samples one delay for each of the three mix layers. The initial
+matrix uses independent exponential samples, consistent with the evaluated
+Poisson-mix literature and maintained Katzenpost design. A constant-delay mode
+exists only for sensitivity tests and does not define a candidate profile.
+
+Modeled forward latency includes five configured link delays, four configured
+KEMSphinx processing costs, and three sampled mix delays. It excludes entry
+capsule processing, queues, wire handshakes, reassembly, storage, replies,
+imports, retries, and user offline time.
+
+### 3.5 Compromise and active suppression
+
+Each entry and mix is independently marked compromised once per replication
+using configured probabilities. Target route metrics record:
+
+- at least one compromised mix;
+- all three mixes compromised;
+- entry compromised;
+- entry and all three mixes compromised;
+- whether repeated messages eventually use a fully compromised mix route.
+
+The active sensitivity scenario allows a compromised mix to suppress each
+non-target packet independently while always forwarding target packets. This
+is a conservative isolation mechanism, not a complete strategic n-1 attacker.
+It does not infer target packets from encrypted content or model loop-based
+detection and response.
+
+## 4. Metrics
+
+### 4.1 Latency and bandwidth
+
+The report publishes nearest-rank p50, p95, p99, minimum, maximum, and mean
+real-message latency. Core bandwidth counts the actual number of traversed
+links, so suppression reduces downstream byte cost while increasing loss.
+
+### 4.2 Local pool size and entropy
+
+At each target departure from an honest mix, the simulator counts packets
+resident in that mix delay pool. Under the memoryless Poisson-mix assumption,
+the local equal-likelihood entropy proxy is:
+
+```text
+H_local = log2(resident_packet_count)
+```
+
+It also records whether every honest mix on a target route had pool size one.
+This is local opportunity for confusion, not the end-to-end posterior entropy
+of a global observer.
+
+### 4.3 Timing candidate proxy
+
+For each target egress, the simulator counts all delivered packets inside a
+configured centered timing window. A count of one is reported as a unique
+timing candidate.
+
+The metric ignores route likelihood, delay likelihood, ingress history,
+multiple links, user schedules, and machine-learned correlation. It is useful
+only for comparing scenario density under identical rules.
+
+### 4.4 Long-term disclosure proxy
+
+For each target send, the simulator observes the recipients of all delivered
+packets in the following configured interval. It intersects these recipient
+sets across repeated sends and records whether the true fixed recipient is
+still present or uniquely identified.
+
+This deliberately transparent construction demonstrates intersection risk. It
+is not the formal statistical disclosure attack, a probabilistic posterior,
+or the third-party unlinkability metric from the research literature.
+
+## 5. First Scenario Matrix
+
+The initial checked-in configurations compare:
+
+1. a 30-user, one-route functional PoC without cover;
+2. a 100-user, two-mix-per-layer alpha with one cover packet per user per hour;
+3. the same alpha with one cover packet every two minutes per user;
+4. the same covered alpha with mean mix delay raised from 500 ms to 5 seconds;
+5. a 1,000-user, three-mix-per-layer sparse topology;
+6. a sparse alpha with 50 percent independent entry and mix compromise input;
+7. a covered alpha with the same compromise input and 95 percent selective
+ background suppression.
+
+These values are intentionally separated sensitivity points. They are not
+recommended operational defaults.
+
+## 6. Initial Results
+
+### 6.1 Sparse use remains exposed
+
+The no-cover PoC had pool size one at every target departure, a unique
+ten-second timing candidate in 99.2 percent of target messages, and unique
+recipient intersection by five observations in every replication.
+
+The sparse alpha used about 8.47 MiB of five-link core traffic per simulated
+hour and a cover-to-real ratio near 9.9. Its local pool p50 remained one,
+96.8 percent of target routes were isolated at every honest mix, and the
+recipient intersection median fell from 63 candidates after one observation
+to two after ten.
+
+These scenarios support only the existing conclusion that a small or idle
+network cannot acquire anonymity through packet cryptography alone.
+
+### 6.2 Cover and delay protect different proxies
+
+One cover packet every two minutes per user raised five-link core traffic to
+about 231.74 MiB/hour and the cover-to-real ratio to about 294. It removed
+unique ten-second timing candidates and kept all 99 possible recipients in the
+one-hour intersection proxy through ten observations.
+
+With mean mix delay still 500 ms, however, local pool p50 remained one and
+64.9 percent of target routes were isolated at every honest mix. Raising mean
+delay to five seconds at the same traffic level raised local pool p50 to three,
+local entropy p50 to about 1.585 bits, and removed fully isolated target routes
+in the 37 target samples. Modeled latency p50 increased from about 1.44 seconds
+to 13.29 seconds.
+
+Cover volume, mixing overlap, observation windows, and latency are therefore
+different dimensions. A strong result in one proxy does not substitute for
+the others.
+
+### 6.3 More users do not automatically solve dilution
+
+The 1,000-user scenario improved the timing-candidate p50 to four and retained
+a median 14 recipient candidates after ten observations. It also spread
+traffic across three nodes per layer. Local pool p50 remained one and 84.2
+percent of target routes were isolated at every honest mix.
+
+Scaling topology and scaling traffic must be evaluated together. Adding nodes
+without enough traffic per node can dilute mixing opportunity.
+
+### 6.4 Repeated compromise exposure is non-zero
+
+With independent 50 percent compromise inputs in the two-node-per-layer
+alpha, 5.5 percent of sampled target routes used compromised nodes in all
+three layers. Three of sixteen replications encountered at least one such
+route. Entry and all three mixes were compromised together on 1.1 percent of
+target routes.
+
+These sampled values are dependent on entry reuse, topology sampling, route
+reuse, and small target counts. They are not analytical probabilities. They
+do show why repeated routing and long-lived observation must be measured, and
+why declared operator diversity does not remove concealed control risk.
+
+### 6.5 Selective suppression destroys the traffic condition
+
+The n-1 sensitivity scenario delivered only 7.9 percent of all emitted
+packets. Its honest local pool p50 returned to one, 89.5 percent of target
+routes with an honest mix were fully isolated, and half the replications saw a
+fully compromised target route.
+
+This model does not yet determine a shutdown threshold. It confirms that cover
+generation without loop health, anomaly evidence, bounded degraded behavior,
+and active-attack analysis is insufficient.
+
+## 7. Decisions From This Baseline
+
+The baseline establishes only the following stable project decisions:
+
+- retain a deterministic, independent discrete-event simulator before daemon
+ implementation;
+- keep packet geometry fixed and route-family validation enabled in every
+ scenario;
+- reject the functional PoC as anonymity evidence;
+- do not choose cover or delay parameters from intuition or a single metric;
+- measure traffic density per mix, not user count or node count alone;
+- keep active suppression and passive compromise as separate scenarios;
+- withhold degraded-mode thresholds until loop, queue, loss, and operational
+ models exist.
+
+No numeric cover, delay, topology, entry-rotation, polling, or shutdown profile
+is selected.
+
+## 8. Required Extensions
+
+Before the local PoC parameter set is frozen, add:
+
+- end-to-end posterior and Shannon-entropy propagation for a declared
+ observer;
+- formal third-party unlinkability and statistical-disclosure experiments;
+- user availability, non-uniform social graphs, bursts, retries, and traces;
+- forward and reply paths, SURBs, acknowledgments, and rendezvous behavior;
+- storage reads, empty polling, writes, receipts, and capability rotation;
+- loop traffic, loss attribution, n-1 detection, false positives, and
+ degraded-mode state machines;
+- queue service capacity, bandwidth ceilings, congestion, jitter, drops, and
+ flood distributions;
+- topology churn, epochs, provider and ASN correlations, hidden operator
+ families, and compromised-position sweeps;
+- confidence intervals and larger independent replication sets;
+- calibration against PoC traces without collecting privacy-unsafe event logs.
+
+## 9. Reproduction and Checks
+
+From `sim/`:
+
+```sh
+gofmt -d cmd/fog-sim/*.go internal/sim/*.go
+go test ./...
+go test -race ./...
+go vet ./...
+go run ./cmd/fog-sim -scenario-dir scenarios
+```
+
+The CLI emits JSON only to standard output. Checked-in Markdown results are a
+review-oriented comparison; the deterministic JSON is the complete report.
+
+## 10. Primary References
+
+- Ania M. Piotrowska, *Studying the anonymity trilemma with a discrete-event
+ mix network simulator*:
+ <https://arxiv.org/abs/2107.12172>
+- Ania M. Piotrowska et al., *The Loopix Anonymity System*:
+ <https://www.usenix.org/conference/usenixsecurity17/technical-sessions/presentation/piotrowska>
+- George Danezis, *Designing and attacking anonymous communication systems*:
+ <https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-594.html>
+- Katzenpost mix network specification:
+ <https://katzenpost.network/docs/specs/mixnet/>
+- Katzenpost mix decoy loop specification:
+ <https://katzenpost.network/docs/specs/mixdecoy/>
+- FOG threat model: `FOG-THREAT-MODEL.md`
+- FOG architecture: `FOG-ARCHITECTURE.md`
+- FOG wire protocol: `FOG-WIRE.md`
+- FOG KEMSphinx profiles: `FOG-SPHINX-PROFILES.md`
diff --git a/docs/FOG-SPHINX-PROFILES.md b/docs/FOG-SPHINX-PROFILES.md
new file mode 100644
index 0000000..f1d32de
--- /dev/null
+++ b/docs/FOG-SPHINX-PROFILES.md
@@ -0,0 +1,1188 @@
+# FOG Sphinx Profiles
+
+Status: Draft 0.1
+
+Date: 2026-08-08
+
+## 1. Purpose
+
+This document defines `FOG-SPHINX-PROFILES`, the authenticated profile
+framework for fixed-size KEMSphinx packets used by FOG.
+
+It fixes the structural packet contract, route shape, routing commands, SURB
+rules, replay behavior, wire ownership, SDK boundary, transition behavior,
+and conformance evidence required before a concrete packet suite can be
+activated.
+
+It also records one calculated but non-active candidate geometry named
+`FOG-SPHINX-CANDIDATE-MLKEM768-X25519-1`. The candidate is an engineering
+input for benchmarks and review. It is not yet `FOG-SPHINX-1`, is not
+authorized for a public network, and does not make a deployed security claim.
+
+The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, and MAY describe
+normative requirements in the sense of BCP 14 when they appear in uppercase.
+
+## 2. Scope
+
+`FOG-SPHINX-PROFILES` owns:
+
+- immutable packet-profile identifiers and their consensus authorization;
+- fixed KEMSphinx packet geometry and exact route length;
+- the mapping from PKI nodes to 32-byte packet node identifiers;
+- per-hop routing command sequences and command padding;
+- forward payload and SURB slots;
+- single-use reply blocks and private reply tokens;
+- replay-tag derivation, durable replay-state behavior, and retirement;
+- packet lifetime and epoch binding;
+- the logical bodies carried by FOG-WIRE packet commands;
+- parser limits, uniform failures, and key lifecycle;
+- conformance-vector and SDK requirements;
+- isolation requirements for foreign Sphinx-family bridges.
+
+This document does not own:
+
+- message-level end-to-end encryption;
+- contact, retry, acknowledgement, or application deduplication semantics;
+- entry-capsule encryption and blind-relay entry selection;
+- rendezvous capability allocation and offline return import;
+- storage capabilities or replica protocols;
+- adjacent-link Noise framing or its record size;
+- the concrete delay distribution and cover rate;
+- consensus production, signatures, or topology assignment.
+
+Those contracts belong to FOG-MESSAGING, FOG-STORAGE, the entry-capsule and
+return-rendezvous specifications, FOG-WIRE, the cover profile, and FOG-PKI.
+
+## 3. Security Boundaries
+
+KEMSphinx protects per-hop routing information and transforms the packet at
+every hop. It does not replace message-level encryption. The terminal receives
+the fixed outer FOG payload and MUST still treat the native message or storage
+operation as end-to-end encrypted unless the owning application protocol
+explicitly defines a different public object.
+
+FOG-WIRE authenticates adjacent links but does not replace KEMSphinx. A valid
+Noise connection is only a carrier for one packet whose KEMSphinx
+authentication, route command, replay status, epoch, and geometry must still
+be validated.
+
+Fixed packet size alone does not provide anonymity against timing,
+intersection, n-1, volume, active tagging, or global observation. Delay,
+traffic volume, cover traffic, topology, endpoint safety, and operator
+independence remain necessary parts of any anonymity claim.
+
+## 4. Protocol Invariants
+
+### SPHINX-INV-01: One exact profile per epoch context
+
+A packet is processed under exactly one packet profile selected by the
+accepted consensus and the authenticated FOG-WIRE epoch context. A node MUST
+NOT guess a profile from packet length, try a list of suites, negotiate a
+suite inside a packet, or fall back after failure.
+
+### SPHINX-INV-02: Four KEMSphinx hops
+
+Every core forward route and every core reply route has exactly four
+KEMSphinx hops. A shorter or longer core route is invalid even if an
+underlying Sphinx library can pad a variable path to the same header length.
+
+### SPHINX-INV-03: Entry is outside the forward mix route
+
+The forward entry is not a KEMSphinx hop. The blind relay submits an
+entry-bound capsule; the entry releases the already constructed packet only
+to its bound layer-1 node.
+
+### SPHINX-INV-04: One transform per hop
+
+An accepted KEMSphinx hop performs one and only one unwrap. No role unwraps
+two layers, forwards a packet without the required unwrap, or changes a route
+outside the authenticated command obtained from that unwrap.
+
+### SPHINX-INV-05: Fixed external geometry
+
+Every packet using one packet profile has one exact byte length. Forward,
+reply, padding, loop, drop, mailbox, and asynchronous-message packets use the
+same geometry. Source applications do not select packet sizes.
+
+### SPHINX-INV-06: Durable replay before action
+
+After successful KEM decapsulation and header authentication, a hop MUST
+atomically check and durably insert its replay identifier before scheduling,
+forwarding, terminal delivery, or returning success to an upstream worker.
+
+### SPHINX-INV-07: Single-use replies
+
+A SURB, its private decryption token, its `surb_id`, and the associated return
+rendezvous are single-use. Uncertain delivery burns them. Retrying with the
+same reply material is forbidden.
+
+### SPHINX-INV-08: No packet-layer fragmentation identity
+
+KEMSphinx packets contain no application message identifier, fragment index,
+or fragment count. Application fragmentation occurs inside the fixed opaque
+user payload under the owning end-to-end protocol.
+
+### SPHINX-INV-09: Purpose-separated keys and state
+
+Mix KEM keys, terminal KEM keys, Noise keys, entry-capsule keys, replay-state
+protection keys, SURB private tokens, message keys, and storage keys are
+distinct. Sharing one private key or replay database across roles is
+forbidden.
+
+### SPHINX-INV-10: Failure never changes topology or profile
+
+Failure cannot remove a layer, substitute the entry as a mix, route directly
+to storage, activate an old profile, send plaintext, or hand a foreign packet
+to a core parser.
+
+## 5. Terminology and Encoding
+
+Terms used in this specification:
+
+- **packet profile**: permanent mapping from a numeric identifier to exact
+ KEMSphinx primitives, geometry, commands, epoch rules, limits, and SDK
+ behavior;
+- **packet epoch context**: the epoch and accepted consensus already bound by
+ the FOG-WIRE connection carrying the packet;
+- **packet node ID**: fixed 32-byte KEMSphinx routing identifier derived from
+ one consensus-authorized node and one packet profile;
+- **forward route**: layer 1, layer 2, layer 3, then a courier or native
+ terminal;
+- **reply route**: layer 3, layer 2, layer 1, then an entry return
+ rendezvous;
+- **SURB**: a public Single Use Reply Block given to a terminal;
+- **private reply token**: Composer-only payload decryption material paired
+ with one SURB;
+- **raw replay tag**: profile-domain-separated digest of the current hop KEM
+ ciphertext;
+- **stored replay ID**: keyed local representation committed to durable replay
+ state.
+
+All integers defined directly by FOG are unsigned and encoded in network byte
+order. Fixed arrays have exactly the declared length. Reserved and padding
+bytes are zero after decryption. Parsers reject non-zero reserved bytes,
+truncation, trailing bytes, duplicate commands, reordered commands, unknown
+commands, and lengths other than the active profile's exact values.
+
+## 6. Packet Profile Registry
+
+Every `packet_profile_id` is a non-zero unsigned 32-bit integer whose meaning
+is permanent. An identifier MUST NOT be reused for changed bytes, algorithms,
+command rules, route shape, limits, or behavior.
+
+An exact profile record contains at least:
+
+```text
+[
+ packet_profile_id,
+ kemsphinx_format_id,
+ kem_suite_id,
+ primitive_suite_id,
+ packet_node_id_hash_id,
+ replay_hash_id,
+ replay_store_mac_id,
+ additional_data,
+ hop_count,
+ route_shape_id,
+ command_registry_id,
+ kem_ciphertext_length,
+ header_mac_length,
+ payload_tag_length,
+ sprp_key_material_length,
+ per_hop_routing_info_length,
+ routing_info_length,
+ header_length,
+ surb_length,
+ sphinx_plaintext_header_length,
+ user_forward_payload_length,
+ forward_payload_length,
+ packet_length,
+ delay_profile_id,
+ maximum_packet_lifetime,
+ epoch_drain_limit,
+ parser_limits_profile_id,
+ sdk_contract_id,
+ conformance_vector_set_id
+]
+```
+
+Registry metadata MAY label a reviewed profile `alpha`, `active`, `draining`,
+or `retired`, but that mutable label is not part of the immutable profile
+meaning. Only the accepted consensus authorizes actual use. An incomplete
+candidate does not receive a numeric `packet_profile_id`.
+
+The profile record is published as an immutable release artifact and its
+identifier is listed by FOG-PKI. Consensus `active_profile_ids` selects the
+exact record. Numeric parameters are not operator-tunable.
+
+One packet profile MUST be compatible with the FOG-WIRE command-shape
+registry active on every link that carries it. A consensus containing an
+incompatible pair is invalid.
+
+## 7. Epoch and Profile Selection
+
+The packet bytes do not carry a negotiable profile identifier or epoch. The
+authenticated FOG-WIRE connection context supplies:
+
+- network identity;
+- epoch;
+- accepted consensus hash;
+- link context;
+- wire profile;
+- the one packet profile mapped to that epoch and command shape.
+
+For a given link context and packet class, one epoch maps to exactly one
+packet profile. Old-epoch packets continue only on old-epoch connections
+during the bounded drain interval. A node MUST NOT trial-decrypt an old
+packet with several epoch keys.
+
+A Composer MUST NOT create a packet unless:
+
+```text
+current_time_upper_bound
+ + maximum_route_delay
+ + relay_and_entry_queue_budget
+ + wire_delivery_budget
+ < packet_epoch_hard_expiry
+```
+
+The same check applies to a SURB's expected round trip. A packet or SURB that
+cannot complete within its epoch budget is not created.
+
+## 8. Core Route Shape
+
+### 8.1 Forward route
+
+The only core forward shape is:
+
+```text
+entry capsule -> L1 -> L2 -> L3 -> terminal
+```
+
+The entry capsule is outside this four-hop KEMSphinx packet. Its specification
+must cryptographically bind the exact packet to the exact L1 packet node ID
+without revealing that ID to the blind relay.
+
+The four KEMSphinx hops are:
+
+| Hop | Required role | Required routing result |
+|---:|---|---|
+| 0 | mix layer 1 | delay, then layer 2 |
+| 1 | mix layer 2 | delay, then layer 3 |
+| 2 | mix layer 3 | delay, then selected terminal |
+| 3 | courier or native terminal | terminal recipient and payload |
+
+### 8.2 Reply route
+
+The only core reply shape is:
+
+```text
+terminal uses SURB -> L3 -> L2 -> L1 -> entry rendezvous
+```
+
+The four KEMSphinx hops are:
+
+| Hop | Required role | Required routing result |
+|---:|---|---|
+| 0 | mix layer 3 | delay, then layer 2 |
+| 1 | mix layer 2 | delay, then layer 1 |
+| 2 | mix layer 1 | delay, then entry |
+| 3 | entry | return rendezvous plus `surb_id` |
+
+The reply sender learns the public first-hop packet node ID contained in the
+SURB. It does not learn later hops, the destination relay, or the Composer's
+private reply token.
+
+### 8.3 Eligibility checks
+
+The Composer builds routes only from one accepted full consensus. Every hop
+must have the required role, exact layer, active packet profile, current epoch
+KEM key, endpoint reachability through the next role, and no effective
+revocation. The route must also pass the consensus topology and diversity
+rules.
+
+Each online hop independently verifies that the authenticated upstream role,
+its own role and layer, the next packet node ID, and the next FOG-WIRE context
+match the consensus. A valid header is not sufficient authorization for a
+role-invalid edge.
+
+## 9. Packet Node IDs
+
+KEMSphinx routing uses a fixed 32-byte `packet_node_id`. It is not a private
+key and is not a substitute for the PKI `node_id`.
+
+For profile `P`, it is derived as:
+
+```text
+packet_node_id = HASH32(
+ "FOG-SPHINX-NODE-ID-1" ||
+ u32be(length(network_id)) ||
+ network_id ||
+ u32be(P.packet_profile_id) ||
+ u32be(length(node_id)) ||
+ node_id
+)
+```
+
+`HASH32` is fixed by `packet_node_id_hash_id`. Consensus validation derives
+all active packet node IDs and rejects any duplicate. Nodes build an immutable
+epoch-local lookup table from packet node ID to the exact authorized role,
+layer, KEM key ID, and link endpoint.
+
+Packet node IDs may be logged only in coarse configuration validation. They
+MUST NOT be logged per packet.
+
+## 10. Routing Commands
+
+The core profile uses the maintained Sphinx command model with these exact
+tags:
+
+| Tag | Command | Body length | Meaning |
+|---:|---|---:|---|
+| `0x00` | `NULL` | 0 | terminates command parsing; remaining bytes are zero |
+| `0x01` | `NEXT_NODE` | 64 | 32-byte next node ID and 32-byte next header MAC |
+| `0x02` | `RECIPIENT` | 32 | opaque terminal recipient or return capability |
+| `0x03` | `SURB_REPLY` | 16 | random single-use `surb_id` |
+| `0x80` | `NODE_DELAY` | 4 | unsigned delay in profile-defined units |
+
+Unknown tags are invalid. No vendor command range is accepted by core nodes.
+
+### 10.1 Intermediate mix command sequence
+
+Every nonterminal mix hop contains exactly:
+
+```text
+NODE_DELAY || NEXT_NODE || NULL || zero padding || next KEM ciphertext
+```
+
+The implementation may build commands in an internal representation, but the
+encrypted routing bytes and parser result must preserve this semantic order.
+There is exactly one delay and one next node. Zero delay is valid only if the
+active cover profile explicitly includes it in the same public distribution
+used for real and cover packets.
+
+The `NODE_DELAY` value is validated before queue insertion. Values outside the
+active delay profile, arithmetic overflow, or a deadline past epoch expiry
+cause a uniform drop.
+
+### 10.2 Forward terminal command sequence
+
+The terminal hop contains exactly:
+
+```text
+RECIPIENT || NULL || zero padding || unused zero KEM slot
+```
+
+`RECIPIENT` is a random or derived 32-byte capability defined by the terminal
+contract. It must not be a human address, username, public mailbox name, or
+application-specific string. The terminal validates it before acting on the
+payload.
+
+### 10.3 Reply terminal command sequence
+
+The entry terminal hop contains exactly:
+
+```text
+RECIPIENT || SURB_REPLY || NULL || zero padding || unused zero KEM slot
+```
+
+Here `RECIPIENT` is an opaque short-lived return-rendezvous capability and
+`SURB_REPLY` selects the Composer's private reply token. The entry atomically
+consumes the rendezvous before queueing the returned opaque payload.
+
+### 10.4 Terminal padding
+
+The current maintained KEMSphinx geometry reserves one KEM ciphertext-sized
+tail in every per-hop routing block, including the terminal block. The
+terminal tail is all zero before routing encryption. FOG does not apply the
+possible one-ciphertext optimization until a new separately identified
+profile has complete vectors and interoperability review.
+
+## 11. Forward Plaintext Block
+
+After the terminal KEMSphinx unwrap and payload-tag validation, a forward
+payload has this exact layout:
+
+```text
+offset length field
+0 1 surb_flag
+1 1 reserved
+2 S surb_slot
+2+S U user_payload
+```
+
+`reserved` is zero. `S` is the profile's exact `surb_length`. `U` is the exact
+`user_forward_payload_length`.
+
+`surb_flag` is:
+
+- `0x00`: no usable SURB; the entire `surb_slot` is zero after decryption;
+- `0x01`: `surb_slot` contains one valid SURB for the same packet profile and
+ epoch.
+
+All other values are invalid. The slot always exists and always occupies the
+same bytes. Application code receives exactly `U` opaque bytes and an optional
+validated public SURB. It does not receive short lengths from the packet
+layer.
+
+The 4,096-byte candidate user payload is owned internally by the next
+protocol. FOG-MESSAGING or FOG-STORAGE defines authentication, actual body
+length, padding, fragmentation, retries, deduplication, and acknowledgements
+inside those bytes.
+
+## 12. SURB Contract
+
+### 12.1 Public SURB
+
+The public SURB encoding is exactly:
+
+```text
+prebuilt_kemsphinx_header[header_length] ||
+first_hop_packet_node_id[32] ||
+reply_payload_key_material[sprp_key_material_length]
+```
+
+The packet profile and epoch are supplied by the containing authenticated
+context and the local SURB object. They are not inserted into the opaque SURB
+and do not change its size.
+
+The prebuilt reply path has exactly four hops and ends in the entry terminal
+commands described in section 10.3.
+
+### 12.2 Private reply token
+
+The Composer stores, separately from the public SURB:
+
+```text
+[
+ token_version,
+ packet_profile_id,
+ epoch,
+ surb_id,
+ hard_expiry,
+ status,
+ reverse_order_payload_key_material
+]
+```
+
+For four hops, `reverse_order_payload_key_material` contains five fixed key
+and IV pairs: one per KEMSphinx hop plus the final reply payload pair. In the
+candidate geometry this secret field is 320 bytes.
+
+The token is secret Composer state. It is encrypted and integrity-protected
+at rest under the Composer state profile, excluded from logs and routine
+backups unless the backup design explicitly protects it, and erased after
+successful use, expiry, cancellation, or uncertain duplicate handling.
+
+### 12.3 Single-use state machine
+
+The only valid state transitions are:
+
+```text
+AVAILABLE -> COMMITTED -> CONSUMED
+AVAILABLE -> EXPIRED
+COMMITTED -> BURNED
+```
+
+The terminal changes a public SURB from `AVAILABLE` to `COMMITTED` before
+building or submitting a reply packet. A confirmed local construction error
+before any packet or KEM operation may return it to `AVAILABLE`; after packet
+construction or any send attempt, uncertainty results in `BURNED`.
+
+The Composer atomically changes the private token to `CONSUMED` before
+releasing successfully authenticated plaintext to an application. A second
+return with the same `surb_id` is discarded without another decryption
+attempt.
+
+Applications needing retries provide multiple independently generated SURBs.
+They never clone a SURB or its private token.
+
+### 12.4 Tagging and compulsion limits
+
+SURBs do not remove active-tagging or reply-compulsion risk. Implementations
+MUST apply the same fixed packet schedule, reply size, and terminal queue
+policy to successful replies, errors, and cover outcomes. A terminal cannot
+send arbitrary immediate diagnostic replies outside the cover schedule.
+
+## 13. Replay Protection
+
+### 13.1 Raw replay tag
+
+For an authenticated hop, the raw tag is:
+
+```text
+raw_replay_tag = HASH(
+ "FOG-SPHINX-REPLAY-TAG-1" ||
+ network_id ||
+ u32be(packet_profile_id) ||
+ u64be(epoch) ||
+ kem_key_id ||
+ current_hop_kem_ciphertext
+)
+```
+
+Lengths for variable fields are fixed by the active PKI and packet profiles.
+`HASH` and its output length are fixed by `replay_hash_id`.
+
+The current hop KEM ciphertext is the public ciphertext at the front of the
+current KEMSphinx header, not a future ciphertext hidden in routing data.
+
+### 13.2 Stored replay ID
+
+The durable database stores:
+
+```text
+stored_replay_id = MAC(
+ replay_state_key_epoch,
+ "FOG-SPHINX-REPLAY-STORE-1" || raw_replay_tag
+)
+```
+
+This local keyed representation reduces direct correlation between a stolen
+database and previously captured packet headers. It is not a substitute for
+disk, process, or host protection.
+
+`replay_state_key_epoch` is independently generated per node, packet profile,
+and epoch. It is not derived from a KEMSphinx private key and is never shared
+with another role or node.
+
+### 13.3 Processing order
+
+A hop processes an incoming packet in this order:
+
+1. verify authenticated FOG-WIRE context, exact command body, and packet
+ length;
+2. enforce current epoch, profile, role, layer, upstream, and local key ID;
+3. parse only fixed header offsets;
+4. decapsulate the current KEM ciphertext;
+5. derive hop keys and verify the current header MAC;
+6. derive the raw replay tag and stored replay ID;
+7. atomically check and durably insert the stored replay ID;
+8. parse and validate the exact routing command sequence;
+9. validate next-hop authorization and delay bounds;
+10. transform the packet exactly once;
+11. queue the transformed packet or terminal payload;
+12. erase per-hop shared secrets and temporary keys.
+
+An unauthenticated random ciphertext is not inserted. A header that
+successfully authenticates is inserted before later command validation, even
+when the command, next hop, delay, or terminal capability is invalid. This
+prevents repeated authenticated malformed work from bypassing replay state.
+
+### 13.4 Durable database
+
+Replay insertion is a crash-consistent transaction. The packet is not made
+eligible for forwarding until the write-ahead record or equivalent durable
+commit succeeds. Group commit is permitted only if scheduling and forwarding
+wait for the corresponding durable barrier.
+
+A keyed in-memory filter MAY avoid many exact lookups, but it is only a front
+cache. A positive filter result is confirmed against the exact durable set;
+therefore filter false positives do not discard valid packets.
+
+Replay databases are separated by node, role, packet profile, epoch, and KEM
+key ID. They are excluded from telemetry, snapshots shared across nodes, and
+ordinary backups. Aggregate counts may be exported only under the observer
+privacy profile.
+
+### 13.5 Restart and loss
+
+On restart, a node verifies database integrity, replay-state key availability,
+epoch ownership, and committed sequence state before accepting packets. It
+rebuilds any in-memory filter from the exact durable set.
+
+Missing, rolled-back, corrupt, or unverifiable replay state is fail-closed.
+The node stops packet processing for that profile and epoch. It does not start
+with an empty cache. Service can resume only from safely restored monotonic
+state or a new epoch with fresh KEM and replay-state keys.
+
+### 13.6 Retirement
+
+An epoch replay database and its local key are retained until:
+
+```text
+epoch_hard_expiry
+ + maximum_packet_lifetime
+ + maximum_clock_uncertainty
+ + crash_recovery_margin
+```
+
+has passed. Retirement erases the replay-state key and removes the database
+through the deployment's recoverable secure-deletion policy. No node accepts
+new work merely because an old database still exists.
+
+## 14. KEMSphinx Hop Processing
+
+Every mix worker has fixed-size buffers from its active geometry. It does not
+allocate based on decrypted command values.
+
+For a valid intermediate hop it:
+
+- decrypts the current routing block;
+- obtains the authenticated delay and next node;
+- shifts the routing information according to KEMSphinx;
+- copies the hidden next-hop KEM ciphertext into the public KEM field;
+- applies one payload permutation;
+- commits replay state;
+- enters the bounded delay queue;
+- emits the exact transformed packet on the authorized next link.
+
+For a valid terminal it:
+
+- verifies the terminal command sequence;
+- verifies the final payload integrity tag;
+- validates the fixed forward plaintext block for a forward packet, or
+ returns the still SURB-protected payload and `surb_id` for a reply packet;
+- consumes any terminal or rendezvous capability atomically;
+- hands only the bounded opaque object to the owning role contract.
+
+No mix exposes whether failure was KEM, MAC, replay, command, delay, route,
+queue, payload tag, recipient, or epoch. Remote behavior is the same uniform
+drop class and is subject to the cover schedule.
+
+## 15. Delay Contract
+
+`NODE_DELAY` contains a 32-bit count in the unit fixed by the active delay
+profile. Implementations convert using checked arithmetic and a monotonic
+clock.
+
+The delay profile fixes at least:
+
+```text
+[
+ delay_profile_id,
+ unit_nanoseconds,
+ maximum_encoded_delay,
+ maximum_per_hop_delay,
+ maximum_route_delay,
+ sampling_distribution_id,
+ quantization_rule,
+ queue_deadline_rule,
+ cover_schedule_profile_id
+]
+```
+
+The Composer samples every mix delay from this authenticated distribution.
+Operators do not alter it locally. Mixes validate the encoded value but do not
+resample it. Queue pressure does not convert delayed traffic to immediate
+traffic; overload follows the profile's uniform drop or shutdown behavior.
+
+The initial distribution and numeric limits remain simulation outputs. No
+anonymity or latency claim follows from this structural specification.
+
+`FOG-SIMULATION.md` records an initial 500 ms versus 5 second exponential-delay
+sensitivity comparison. It selects neither value. The longer value improved
+local pool overlap under one high-cover scenario while increasing modeled
+latency by roughly an order of magnitude; formal end-to-end and operational
+evidence remains open.
+
+## 16. Padding and Fragmentation
+
+### 16.1 Packet padding
+
+Routing blocks, forward SURB slots, user payloads, reply payloads, and unused
+fields always occupy their full profile lengths. Plain structural padding is
+zero before the applicable cryptographic layer. Random bytes are used only
+where the selected reviewed construction requires randomness.
+
+Application code MUST NOT create a shorter KEMSphinx payload. It supplies an
+exact fixed-size inner envelope whose internal padding is authenticated by the
+owning end-to-end protocol.
+
+### 16.2 Application fragmentation
+
+Messages larger than `user_forward_payload_length` are fragmented by
+FOG-MESSAGING or FOG-STORAGE before KEMSphinx construction. Fragment metadata
+is inside the end-to-end protected envelope. Each fragment becomes an
+independent fixed-size KEMSphinx packet with independent route randomness,
+KEM ciphertexts, replay tags, and optional SURB.
+
+KEMSphinx does not retransmit or deduplicate fragments. Reusing a packet for a
+retry is forbidden. A retry constructs a fresh packet under the application
+protocol's idempotency rules.
+
+### 16.3 FOG-WIRE fragmentation
+
+`PACKET_FORWARD` and the packet portion released from `PACKET_SUBMIT` are one
+logical FOG-WIRE message with an exact KEMSphinx packet body. FOG-WIRE may
+split that logical message across its fixed DATA records when the active wire
+profile requires it.
+
+Wire fragments are link-local and are fully reassembled, bounded, and
+authenticated before KEMSphinx parsing. They are never individually queued,
+replayed, forwarded, or stored as KEMSphinx packets.
+
+## 17. FOG-WIRE Command Bodies
+
+This document owns these logical command shapes:
+
+```text
+PACKET_FORWARD_BODY = kemsphinx_packet[packet_length]
+
+PACKET_RETURN_BODY =
+ surb_id[16] ||
+ returned_payload[payload_tag_length + forward_payload_length]
+```
+
+`PACKET_FORWARD_BODY` is used for entry-to-L1, mix-to-mix, and L3-to-terminal
+links. Link context and direction determine which role pair is legal.
+
+`PACKET_RETURN_BODY` is created only after the entry completes the final reply
+hop and atomically consumes the return rendezvous. The returned payload remains
+protected by the Composer's private reply token. The relay cannot decrypt or
+modify it successfully.
+
+`PACKET_SUBMIT_BODY` remains owned by the entry-capsule specification because
+it must hide and bind the first internal hop from the blind relay.
+
+A compatible FOG-WIRE command-shape registry has compile-time exact body
+limits for these commands. Generic byte-string RPCs are not conforming.
+
+## 18. Candidate Geometry
+
+### 18.1 Status
+
+The following profile is a calculated candidate:
+
+```text
+name = FOG-SPHINX-CANDIDATE-MLKEM768-X25519-1
+packet_profile_id = UNASSIGNED
+candidate_status = geometry-only
+```
+
+The candidate name is permanently bound to this calculated geometry. It is
+not a complete packet profile because final primitive IDs, dependency
+revisions, delay limits, replay lifetime, and conformance vector IDs are still
+unresolved. A numeric packet profile ID is assigned only after every field in
+section 6 is frozen. It will not reuse an identifier from another candidate.
+
+This candidate MUST NOT be placed in a claim-bearing public consensus until
+section 24's activation gates pass.
+
+`FOG-CRYPTO-SUITES.md` admits the exact calculated construction to
+complete-packet benchmarking but does not activate it. The unresolved
+non-KEM primitives and implementation evidence keep the complete profile
+non-active.
+
+`FOG-CRYPTO-BENCHMARKS.md` records a first-host benchmark of this exact
+geometry. Future implementations MUST preserve its strict integration
+finding: the parameterized maintained API is wrapped by a FOG boundary that
+rejects every path, packet, payload, SURB, encrypted reply, or reply-key length
+that differs from this profile before cryptographic processing. The first-host
+result does not change `geometry-only` status or assign a profile ID.
+
+### 18.2 Candidate primitive inputs
+
+The geometry calculation uses:
+
+- KEMSphinx with one KEM ciphertext per hop;
+- exactly four hops;
+- hybrid `MLKEM768-X25519` built by the maintained HPQC security-preserving
+ split-PRF combiner;
+- component and ciphertext concatenation order of X25519 hashed-ElGamal KEM
+ first, then ML-KEM-768, matching the evaluated HPQC registry despite the
+ display name; the split-PRF is order-sensitive;
+- ML-KEM-768 ciphertext length of 1,088 bytes;
+- X25519 hashed-ElGamal KEM ciphertext length of 32 bytes;
+- combined KEM ciphertext length of 1,120 bytes;
+- 32-byte packet node IDs;
+- 32-byte header MACs;
+- 16-byte SURB IDs;
+- 32-byte payload integrity tags;
+- 48-byte SPRP keys and 16-byte SPRP IVs;
+- two additional-data bytes fixed to `0x0000` for compatibility with the
+ evaluated maintained KEMSphinx format;
+- a two-byte forward plaintext header;
+- a 4,096-byte user forward payload;
+- one fixed SURB slot in every forward plaintext block.
+
+The primitive suite currently evaluated with this geometry includes the
+maintained Katzenpost KDF, header MAC, header stream, and AEZ-based payload
+SPRP parameterization. Geometry compatibility does not constitute approval of
+that primitive suite. In particular, the exact dependency revisions,
+side-channel behavior, licensing, AEZ usage, deterministic vectors, and
+independent review remain activation gates.
+
+### 18.3 Exact calculation
+
+```text
+KEM_CIPHERTEXT_LENGTH = 1088 + 32
+ = 1120
+
+NEXT_NODE_LENGTH = 1 + 32 + 32
+ = 65
+
+SURB_REPLY_LENGTH = 1 + 16
+ = 17
+
+PER_HOP_ROUTING_INFO = 65 + 17 + 1120
+ = 1202
+
+ROUTING_INFO_LENGTH = 4 * 1202
+ = 4808
+
+HEADER_LENGTH = 2 + 1120 + 4808 + 32
+ = 5962
+
+SPRP_KEY_MATERIAL = 48 + 16
+ = 64
+
+SURB_LENGTH = 5962 + 32 + 64
+ = 6058
+
+FORWARD_PAYLOAD = 2 + 6058 + 4096
+ = 10156
+
+PACKET_LENGTH = 5962 + 32 + 10156
+ = 16150
+
+PRIVATE_REPLY_KEYS = (4 + 1) * 64
+ = 320
+```
+
+### 18.4 Candidate geometry table
+
+| Field | Bytes |
+|---|---:|
+| Hop count | 4 hops |
+| Additional data | 2 |
+| KEM ciphertext | 1,120 |
+| Per-hop routing information | 1,202 |
+| Routing information | 4,808 |
+| Header MAC | 32 |
+| Header | 5,962 |
+| Payload tag | 32 |
+| Public SURB | 6,058 |
+| Forward plaintext header | 2 |
+| User forward payload | 4,096 |
+| Forward payload | 10,156 |
+| Complete KEMSphinx packet | 16,150 |
+| Private reply key material | 320 |
+
+Every arithmetic value is a protocol constant for this candidate. Runtime
+configuration cannot change it.
+
+## 19. Key Lifecycle
+
+Every mix and terminal has an independently generated KEMSphinx key for each
+authorized packet profile and epoch. Descriptors bind the public key, key ID,
+purpose, owner node, role, layer, profile, and validity interval.
+
+Private keys:
+
+- are generated with an approved operating-system randomness source;
+- are written only to role-local protected storage;
+- are loaded only by the owning role process;
+- are never copied to another layer, co-located role, authority, relay, or
+ observer;
+- are never used for Noise, entry capsules, storage, signatures, or messages;
+- remain available only for the exact old-epoch drain interval;
+- are erased after packet and replay retirement conditions both hold.
+
+Key generation and persistence are crash-safe. A descriptor is not published
+until the private key is durably available to its owner. A node never creates
+a fresh private key under an already published key ID.
+
+KEM decapsulation failures, malformed public keys, and component failures in
+a hybrid KEM are fatal to that packet. A hybrid implementation must reject
+incorrect component lengths before component decapsulation and must not reveal
+which component failed.
+
+## 20. Parser and Resource Limits
+
+Before cryptographic work, an implementation enforces:
+
+- exact logical message length;
+- exact packet profile from connection context;
+- one bounded packet buffer;
+- no recursive, compressed, map-based, or self-describing packet data;
+- no allocation based on routing commands;
+- no profile or algorithm name supplied by the peer;
+- per-connection, per-peer, per-key, and global cryptographic work budgets;
+- bounded queues and deadlines.
+
+After decryption, it enforces:
+
+- exact command count, type, order, and zero padding;
+- one legal next role and layer;
+- delay bounds and epoch completion bounds;
+- terminal capability length and one-time state;
+- exact forward block flags and zero reserved bytes;
+- exact payload and SURB lengths.
+
+Memory containing shared secrets, per-hop keys, private reply keys, and
+decrypted routing blocks is cleared promptly using the reviewed library's
+supported mechanism. Memory clearing is defense in depth and does not replace
+process isolation.
+
+## 21. Logging and Observability
+
+Core roles MUST NOT log:
+
+- packet bytes or packet digests;
+- raw replay tags or stored replay IDs;
+- KEM ciphertexts or shared secrets;
+- `surb_id`, SURBs, private reply tokens, or rendezvous capabilities;
+- per-packet routes, next-hop IDs, delay values, or fine timing;
+- terminal recipient capabilities or user payloads.
+
+Permitted local diagnostics are coarse reason counters, queue occupancy
+buckets, bounded latency histograms, replay database health state, and
+profile-level totals under FOG-OBSERVER privacy rules. Operators cannot enable
+packet tracing on a claim-bearing profile.
+
+Test builds may use deterministic vectors and verbose traces only with public
+test keys and synthetic packets. Such builds and keys are rejected by
+production configuration.
+
+## 22. SDK Boundary
+
+The stable public SDK exposes typed operations, not raw cryptographic knobs.
+It contains at least:
+
+```text
+ValidatePacketProfile(profile, consensus_context)
+DerivePacketNodeID(profile, node_id)
+BuildForwardRoute(consensus, terminal, rng)
+BuildReplyRoute(consensus, rendezvous, surb_id, rng)
+CreateSURB(profile, epoch, reply_route, rng)
+CreateForwardPacket(profile, route, fixed_payload, optional_surb, rng)
+CreateReplyPacket(profile, public_surb, fixed_payload)
+UnwrapOneHop(profile, epoch_context, private_key, exact_packet)
+DecryptSURBReply(private_token, surb_id, exact_returned_payload)
+```
+
+The SDK does not expose:
+
+- arbitrary hop counts for core profiles;
+- operator-selected algorithms or geometry;
+- raw private-key serialization through ordinary application APIs;
+- reuse or cloning of SURBs or reply tokens;
+- packet parsing without an authenticated profile and epoch context;
+- automatic foreign-profile detection;
+- application-dependent packet sizes.
+
+SURB and private-token types are move-only or guarded by an atomic persistent
+state abstraction. Copyable byte slices are not the primary API.
+
+The same reference codec and vector set are used by Composer, entry, mix,
+terminal, relay import, simulator, and conformance tools. Each executable
+still imports only the operations needed by its role.
+
+## 23. Conformance Evidence
+
+Each packet profile release includes machine-readable vectors generated with
+fixed public test entropy. The vector manifest records dependency versions,
+source revision, profile record hash, and generation command.
+
+The required vector set covers:
+
+1. packet node ID derivation;
+2. hybrid KEM component key and ciphertext lengths;
+3. complete candidate geometry arithmetic;
+4. every routing command encoding and invalid tag;
+5. zero padding and terminal unused KEM slot;
+6. one complete four-hop forward packet at every unwrap;
+7. one complete four-hop SURB reply at every unwrap and final decryption;
+8. replay tags at each hop and durable duplicate rejection;
+9. changed ciphertext, MAC, command, padding, payload tag, and SURB failures;
+10. wrong profile, epoch, role, layer, route length, and upstream failures;
+11. maximum and invalid delay values;
+12. SURB state transitions, double use, expiry, and uncertain send;
+13. replay database restart, rollback, corruption, and retirement;
+14. FOG-WIRE fragmentation and exact logical body reassembly;
+15. profile overlap with separate old and new epoch connections;
+16. cross-implementation byte equality.
+
+Property and fuzz tests additionally cover all fixed-offset parsers,
+truncations at every byte boundary, trailing bytes, unknown commands, command
+reordering, integer boundaries, malformed KEM component lengths, and queue
+resource limits.
+
+At least two independently integrated implementations must reproduce the
+complete vectors before a claim-bearing profile becomes active. Calling the
+same library through two thin wrappers is not independent evidence.
+
+## 24. Activation Gates
+
+`FOG-SPHINX-CANDIDATE-MLKEM768-X25519-1` remains non-active until all of the
+following are complete:
+
+- reproducible create, unwrap, SURB, and replay benchmarks on every supported
+ hardware class using the exact 16,150-byte geometry; the first older x86-64
+ create, unwrap, and SURB baseline is complete, while replay and the remaining
+ hardware classes are open;
+- memory, queue, storage, and maximum-throughput budgets for every role;
+- dependency revision pinning, license review, and reproducible builds;
+- review of the ML-KEM-768 implementation and X25519 adapter;
+- confirmation that the exact security-preserving combiner meets the
+ KEMSphinx hybrid-KEM requirement;
+- review of KDF, MAC, stream, payload SPRP, fragile payload-tag construction,
+ and side-channel behavior;
+- complete deterministic vectors and negative corpus;
+- fuzzing and restart-safe replay tests;
+- simulator evidence for packet size, delay, cover traffic, n-1, and long-term
+ disclosure behavior;
+- compatibility verification with the selected maintained KEMSphinx target;
+- independent protocol and implementation review;
+- a separately documented decision promoting an exact immutable record to
+ `alpha` and later `active`.
+
+Failure of a gate produces a newly named geometry candidate or a newly
+numbered complete packet profile, as applicable. It does not silently change
+this candidate.
+
+## 25. Profile Transitions
+
+A packet-profile transition follows the FOG-PKI preannouncement and bounded
+overlap rules.
+
+During overlap:
+
+- new work uses the profile mapped to the new epoch;
+- old work drains only on old-epoch FOG-WIRE connections;
+- each profile has separate KEM keys, replay-state keys, replay databases,
+ queues, command-shape registry, and SDK object types;
+- a packet is never converted in place from one profile to another;
+- a failure in the new profile does not reactivate the old profile;
+- minimum accepted profile state is monotonic.
+
+After hard expiry, old connections close, old packets and SURBs are rejected,
+private reply tokens expire, replay state completes its retention period, and
+private KEM keys are erased.
+
+Emergency retirement can stop creation and acceptance immediately, but it
+cannot downgrade. In-flight delivery may be lost.
+
+## 26. External Sphinx-Family Bridges
+
+Foreign Sphinx, KEMSphinx, Katzenpost, Nym, YAMN, SMTP, NNTP, and other network
+formats never enter a core packet parser. A bridge has:
+
+- a separate `fog-bridge-*` executable and service identity;
+- separate ports, FOG-WIRE link context, keys, writable state, queues, replay
+ domains, metrics, and deployment policy;
+- one explicitly named foreign profile and version;
+- strict parsing and resource bounds for that profile only;
+- no access to Composer plaintext or core private keys;
+- a fresh core packet constructed after policy validation, never a header
+ reinterpretation or in-place conversion;
+- explicit disclosure as a correlation and availability point.
+
+A bridge terminates one network anonymity context and originates another. It
+cannot claim end-to-end mix-path unlinkability across the boundary, even when
+the application payload remains end-to-end encrypted.
+
+Automatic port sharing, packet sniffing, trial parsing, or silent downgrade
+between core and foreign profiles is forbidden.
+
+## 27. Failure Matrix
+
+| Condition | Required behavior |
+|---|---|
+| Wrong packet length | reject before KEM work |
+| Wrong epoch or profile context | reject, no alternate-key trial |
+| KEM decapsulation failure | uniform drop |
+| Header MAC failure | uniform drop, no durable replay insertion |
+| Authenticated duplicate | uniform drop after exact replay lookup |
+| Authenticated invalid command | durable replay insert, then uniform drop |
+| Invalid next role or layer | durable replay insert, then uniform drop |
+| Invalid delay or expired deadline | durable replay insert, then uniform drop |
+| Replay commit failure | stop affected profile and epoch processing |
+| Replay state missing or rolled back | fail closed until safe restore or new epoch |
+| Delay queue overload | profile-defined uniform drop or role shutdown |
+| Final payload tag failure | uniform drop, no terminal action |
+| Invalid terminal capability | uniform drop after one-time-state rules |
+| SURB reused or expired | discard without constructing another reply |
+| Private token missing or consumed | discard returned payload |
+| Old profile failure during transition | do not fall back or extend expiry |
+| Foreign packet on core port | reject before foreign parsing |
+
+Local diagnostics use coarse stable reason classes. Remote peers receive no
+fine-grained error response.
+
+## 28. Threat Traceability
+
+| Threat-model concern | Packet-profile response |
+|---|---|
+| `TM-NET-01` traffic correlation | one fixed geometry, four hops, authenticated delay and cover profile |
+| `TM-NET-02` low anonymity set | no packet-format claim; simulator and deployment gates remain required |
+| `TM-NET-03` compromised mixes | stratified route, one transform, role validation, purpose-separated keys |
+| `TM-NET-04` replay and compulsion | durable per-hop replay, single-use SURBs and rendezvous state |
+| `TM-NET-05` tagging | authenticated header and payload processing, uniform terminal failure |
+| `TM-NET-06` profile fingerprinting | consensus-selected immutable profiles, no autodetection or negotiation |
+| `TM-PKI-02` stale consensus | epoch-bound packet context and monotonic transition state |
+| `TM-ROLE-01` role collapse | separate KEM keys, replay state, ports, commands, and bridge processes |
+| `TM-ROLE-02` relay knowledge | entry capsule hides L1; relay handles only opaque fixed packets |
+| `TM-ROLE-03` terminal exposure | terminal gets fixed opaque application payload, not source address or full route |
+| `TM-CRYPTO-01` primitive misuse | reviewed parameterized library, immutable suite record, activation gates |
+| `TM-CRYPTO-02` key reuse | role, purpose, profile, and epoch separation |
+| `TM-AVAIL-01` resource exhaustion | fixed buffers, crypto budgets, durable replay, bounded queues and failures |
+
+## 29. Residual Risks
+
+Even a conforming implementation remains exposed to:
+
+- traffic analysis from timing, volume, routes, endpoints, and sparse use;
+- n-1 and active-delay attacks by sufficiently placed malicious nodes;
+- denial of service through connection, KEM, replay-store, queue, or terminal
+ exhaustion within residual budgets;
+- endpoint or Composer compromise;
+- malicious or colluding entry, mix, terminal, relay, storage, and authority
+ operators within the threat model's residual cases;
+- reply tagging and compulsion not eliminated by SURBs;
+- implementation, dependency, side-channel, randomness, and erasure defects;
+- correlation introduced by external bridges;
+- loss caused by fail-closed replay and single-use reply behavior;
+- incorrect anonymity conclusions from a local PoC or low-traffic network.
+
+These risks must appear in deployment documentation and public claims.
+
+## 30. References
+
+- George Danezis and Ian Goldberg, *Sphinx: A Compact and Provably Secure Mix
+ Format*, 2009: <https://eprint.iacr.org/2008/475>
+- Katzenpost, *The KEMSphinx Cryptographic Packet Format*:
+ <https://katzenpost.network/docs/specs/kemsphinx/>
+- Katzenpost, *The Sphinx Cryptographic Packet Format*:
+ <https://katzenpost.network/docs/specs/sphinx/>
+- Katzenpost, *The Katzenpost Mix Network Wire Protocol*:
+ <https://katzenpost.network/docs/specs/mixnet/>
+- Katzenpost, *Katzenpost Mix Network Replay Detection*:
+ <https://katzenpost.network/docs/specs/packet_replay/>
+- Federico Giacon, Felix Heuer, and Bertram Poettering, *KEM Combiners*,
+ 2018: <https://eprint.iacr.org/2018/024>
+- NIST, *FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism Standard*,
+ 2024: <https://csrc.nist.gov/pubs/fips/203/final>
+- RFC 7748, *Elliptic Curves for Security*:
+ <https://www.rfc-editor.org/rfc/rfc7748>
+- FOG Composer protocol: `FOG-COMPOSER.md`
+- FOG cryptographic suite evaluation: `FOG-CRYPTO-SUITES.md`
+- FOG cryptographic benchmark baseline: `FOG-CRYPTO-BENCHMARKS.md`
+- FOG traffic and topology simulation: `FOG-SIMULATION.md`
+
+## 31. Completion Checklist
+
+Before implementation work for an active packet profile begins, reviewers
+must be able to answer yes to all of these questions:
+
+- Is one immutable profile selected by authenticated consensus and epoch
+ context without packet guessing?
+- Are both directions exactly four KEMSphinx hops with the entry outside the
+ forward route?
+- Are packet, header, routing, payload, SURB, and reply-token sizes proven by
+ arithmetic and tests?
+- Are command sequences exact, padded, role-valid, and parser-bounded?
+- Is replay state durable before forwarding and fail-closed after rollback or
+ loss?
+- Are SURBs, private tokens, IDs, and rendezvous capabilities atomic and
+ single-use?
+- Is application fragmentation inside end-to-end protection and independent
+ of packet size?
+- Are KEM, replay, Noise, entry, storage, and message keys purpose-separated?
+- Do FOG-WIRE command shapes and packet geometry agree exactly?
+- Are complete vectors, fuzzing, benchmarks, simulation, and independent
+ review available for the exact dependency set?
+- Are external formats isolated in separate bridge processes and disclosed as
+ correlation points?
+- Do failures stop safely without topology, profile, or plaintext fallback?
diff --git a/docs/FOG-STORAGE.md b/docs/FOG-STORAGE.md
new file mode 100644
index 0000000..00498ac
--- /dev/null
+++ b/docs/FOG-STORAGE.md
@@ -0,0 +1,1507 @@
+# FOG Storage
+
+Status: Draft 0.1
+
+Date: 2026-08-08
+
+## 1. Purpose
+
+This document defines `FOG-STORAGE`, the capability-addressed scattered
+storage contract used by FOG native asynchronous services.
+
+It fixes the storage trust boundaries, pairwise stream model, rotating box
+capabilities, storage-epoch manifests, courier envelopes, replica selection,
+single-box read and write operations, authenticated replica receipts,
+idempotency, request retry and deduplication, empty-read behavior, retention,
+tombstones, repair, resource bounds, and conformance gates.
+
+It also records a non-active integration candidate named
+`FOG-STORAGE-CANDIDATE-BACAP-PIGEONHOLE-1`. The candidate evaluates the
+published BACAP construction and the single-box portion of the published
+Pigeonhole protocol while preserving FOG role separation and packet profiles.
+It is not `FOG-STORAGE-1`, has no numeric profile identifier, is not directly
+wire-compatible with Katzenpost, is not authorized for a public network, and
+does not establish a deployed security claim.
+
+The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, and MAY describe
+normative requirements in the sense of BCP 14 when they appear in uppercase.
+
+## 2. Scope
+
+`FOG-STORAGE` owns:
+
+- storage stream, read-capability, write-capability, and per-box state;
+- private per-contact directional mailbox streams;
+- immutable public storage-replica manifests;
+- storage epochs and replica envelope-key periods;
+- fixed Composer-to-courier storage envelopes and replies;
+- fixed courier-to-replica and replica-to-replica command bodies;
+- deterministic final-shard selection and disjoint intermediate selection;
+- single-box reads, data writes, tombstone writes, and authenticated results;
+- courier request deduplication and bounded request state;
+- idempotent final-replica behavior and replica repair;
+- retention, garbage collection, backup deletion, and non-resurrection rules;
+- fixed geometry compatibility with FOG-MESSAGING, KEMSphinx, and FOG-WIRE;
+- storage overload, flooding, and non-amplification requirements;
+- parser limits, failure behavior, lifecycle, and conformance evidence.
+
+This document does not own:
+
+- message identities, ratchets, application frames, or message ACK semantics;
+- KEMSphinx packet construction, SURB cryptography, or packet replay state;
+- adjacent-link Noise framing or connection scheduling;
+- Composer local-database encryption and rollback detection;
+- the entry capsule, return rendezvous, or offline transfer bundle;
+- concrete cover, polling, retry-delay, or traffic-rate distributions;
+- anonymous client admission or a general anti-Sybil solution;
+- multi-box atomic copy, group delivery, multi-device synchronization, or
+ permanent archival storage.
+
+Those contracts belong to `FOG-MESSAGING`, `FOG-SPHINX-PROFILES`, `FOG-WIRE`,
+`FOG-COMPOSER`, the entry and return specifications, `FOG-SX`, the cover
+profile, future admission work, and future group or bulk-delivery protocols.
+
+## 3. Security Boundary and Information Exposure
+
+### 3.1 Composer
+
+The networkless Composer is the only role that holds stream root capabilities,
+derives successive box identifiers and box keys, encrypts or decrypts box
+payloads, verifies box authenticity, constructs storage envelopes, and makes
+the final decision to advance a stream index.
+
+The Composer learns its contact relationship, stream direction, box sequence,
+message envelope, retry state, replica selection, and detailed local result.
+None of those data classes may be delegated to the blind relay.
+
+### 3.2 Courier
+
+The courier terminates the final KEMSphinx hop and sees:
+
+- one fixed storage profile and storage epoch;
+- the exact storage-manifest hash;
+- two intermediate replica identifiers and envelope-key identifiers;
+- a fixed client ephemeral public key, two fixed encapsulations, and one
+ fixed opaque ciphertext;
+- a short-lived hash used only for request deduplication and reply matching;
+- coarse acceptance, timeout, and local overload state.
+
+The courier MUST NOT learn the box ID, stream capability, stream index,
+operation type, final shard pair, message ID, contact, application type,
+plaintext, data-versus-tombstone state, or empty-versus-hit result.
+
+### 3.3 Intermediate replica
+
+Each intermediate replica opens one addressed envelope and learns one fixed
+inner storage request, including the box ID, operation type, storage epoch,
+operation nonce, and deterministic final shard pair. It does not learn the
+Composer network location, contact identity, stream root, stream index,
+application type, or message plaintext.
+
+An intermediate replica MUST NOT persist a mailbox, capability root, or
+unbounded request history. It keeps only bounded dispatch and reply state.
+
+### 3.4 Final replica
+
+Each final replica learns the box ID, operation type, storage epoch, signed
+opaque box record, and the intermediate replica that forwarded the request.
+It stores only the fixed authenticated record or tombstone in the selected
+storage-epoch namespace.
+
+A final replica cannot identify the stream to which a box belongs unless the
+capability construction, client behavior, collusion, or side information
+breaks that unlinkability objective. Repeated reads of the same still-empty
+box are necessarily linkable at a final replica and remain a documented
+residual risk.
+
+### 3.5 Blind relay, entry, and mixes
+
+These roles see only their existing fixed transfer, entry, KEMSphinx, and
+FOG-WIRE objects. They do not parse a FOG-STORAGE field. Storage protection
+does not replace KEMSphinx or Noise, and those layers do not replace box and
+envelope protection.
+
+## 4. Protocol Invariants
+
+### STORE-INV-01: No stable public mailbox
+
+A FOG mailbox is a private stream capability and an evolving sequence of
+pseudorandom box IDs. The protocol has no public mailbox name, user lookup,
+stable network account, or direct Composer-to-replica endpoint.
+
+### STORE-INV-02: One writer per stream
+
+One stream has exactly one active write-capability holder. Bidirectional
+messaging uses two independent streams, one per direction. Concurrent copies
+of one write state or multiple writers are invalid.
+
+### STORE-INV-03: Capability authority is explicit
+
+A read capability can derive future box locations, verify records, and decrypt
+the corresponding payloads. A write capability can additionally derive
+signing and encryption material, create data records, and create tombstones.
+If the selected construction lets a writer derive the read capability, FOG
+MUST state that fact and MUST NOT present write-only confidentiality as a
+property.
+
+### STORE-INV-04: Box locations rotate
+
+Every stream index derives a new pseudorandom box ID and per-box key state.
+Online roles MUST NOT receive a stream root or a stable capability from which
+they can enumerate the sequence.
+
+### STORE-INV-05: Four independent replicas minimum
+
+A claim-bearing deployment has at least four eligible storage replicas. Two
+final replicas are selected deterministically for a box, and the Composer
+selects two distinct intermediate replicas outside that final pair. Fewer
+than four disables the intermediate/final disjointness claim rather than
+triggering silent fallback.
+
+### STORE-INV-06: Immutable data, authoritative tombstone
+
+The first valid data record at an empty box is immutable. An exact duplicate
+is idempotent success. A different data record at the same box is conflict.
+Only a valid tombstone from the box writer can replace data, and data can never
+replace a committed tombstone within that storage-epoch namespace.
+
+### STORE-INV-07: Persist before export or advancement
+
+The Composer MUST atomically persist the next stream state, exact immutable
+box record, recovery tombstone, request generation, and outbox state before
+export. A reader advances only after the complete storage and owning upper
+protocol transition commits.
+
+### STORE-INV-08: Retry has two distinct layers
+
+Within one courier request generation, every retransmission uses the exact
+same fixed `CourierEnvelope` so the courier can deduplicate it. Every network
+transmission uses a fresh KEMSphinx packet, route randomness, entry material,
+SURB, private reply token, and rendezvous. A later request generation may
+reencrypt the same immutable box operation only under explicit bounded rules.
+
+### STORE-INV-09: Storage ACK is not message delivery
+
+Courier acceptance means only that the courier accepted bounded work.
+Replica commit means only that the stated replicas durably committed a box
+record. Neither means that a recipient Composer fetched, authenticated,
+committed, displayed, or read the FOG message.
+
+### STORE-INV-10: Empty read never advances state
+
+A signed empty result means only that selected replicas observed no record for
+that box and epoch when they processed the request. It does not prove permanent
+absence and MUST NOT advance the read capability.
+
+### STORE-INV-11: Fixed traffic classes
+
+Reads, data writes, tombstone writes, hits, misses, conflicts, retries,
+expected errors, and cover operations use the same profile-fixed KEMSphinx and
+FOG-WIRE geometry. Timing normalization remains owned by the cover profile.
+
+### STORE-INV-12: Bounded retention, not archival storage
+
+Every record, tombstone, key, dedup entry, retry, repair item, and backup copy
+has a profile-defined upper lifetime. A peer-supplied timestamp cannot extend
+it. FOG does not promise indefinite offline delivery.
+
+### STORE-INV-13: No capability at the courier
+
+The courier MUST NOT receive a stream read cap, stream write cap, per-contact
+capability root, or a temporary stream capability from which it can enumerate
+boxes. The initial profile therefore excludes Pigeonhole `CopyCommand` and
+AllOrNothing processing.
+
+### STORE-INV-14: No downgrade or dynamic shard substitution
+
+Profiles, storage manifests, shard count, intermediate count, geometry, and
+epoch windows are authenticated. Failure MUST NOT select arbitrary replicas,
+reuse an old manifest, reduce the replica count, bypass the courier, or parse a
+different storage construction.
+
+## 5. Terminology
+
+- **stream**: one single-writer sequence of independently addressed boxes;
+- **write capability**: secret state that derives future box signing,
+ encryption, addressing, and tombstone authority;
+- **read capability**: secret state that derives future box addressing,
+ verification, and decryption authority but cannot create valid records;
+- **box index state**: evolving counter and KDF state for one stream direction;
+- **box ID**: pseudorandom fixed identifier that also participates in record
+ verification under the selected capability construction;
+- **box record**: one fixed authenticated encrypted payload or tombstone;
+- **storage epoch**: storage-specific key and retention period, distinct from
+ the shorter FOG-PKI network epoch;
+- **storage manifest**: immutable authority-authenticated replica set, key set,
+ profile, geometry, and lifetime for one storage epoch;
+- **final replicas**: the two manifest replicas selected deterministically for
+ one box ID;
+- **intermediate replicas**: two distinct non-final replicas selected by the
+ Composer to hide the final pair from the courier;
+- **courier request generation**: one immutable envelope and short-lived
+ courier deduplication lifetime;
+- **operation nonce**: random per-generation value visible only after replica
+ envelope decryption and bound into final-replica receipts;
+- **replica receipt**: final-replica-authenticated statement about one box
+ operation at one epoch and operation nonce;
+- **miss**: authenticated observation that no record was present, not proof of
+ permanent nonexistence;
+- **tombstone**: writer-authenticated empty record that prevents later data
+ resurrection until the namespace expires.
+
+All integers defined directly by FOG are unsigned network byte order. Fixed
+arrays have exactly the profile-defined length. Reserved and padding bytes are
+zero after authenticated decryption. Parsers reject truncation, trailing
+bytes, non-zero reserved fields, counter wrap, unknown-critical values, and
+lengths other than the exact active profile geometry.
+
+## 6. Stream and Mailbox Model
+
+### 6.1 Directional pairwise streams
+
+One pairwise FOG conversation uses two independent streams:
+
+```text
+Alice writer -> Bob reader
+Bob writer -> Alice reader
+```
+
+Each stream root is unique to one relationship, direction, profile, and
+generation. Reusing a stream across contacts, applications, groups, or both
+directions is forbidden.
+
+When Bob gives Alice an inbound mailbox grant, Bob first creates the stream,
+persists his reader state, and exports the corresponding writer state to
+Alice. Alice can then write the stream and, under the BACAP candidate, derive
+its read state and tombstone its boxes. This is acceptable only because that
+stream contains Alice's own deposits to Bob and no other contact's data.
+
+The grant MUST NOT provide access to Bob's other inbound streams, outbound
+streams, capability registry, message history, local database, storage backup,
+or identity keys.
+
+### 6.2 Capability issuance
+
+Before exporting a stream grant, the issuing Composer MUST atomically persist:
+
+- the exact storage profile and stream generation;
+- the initial box index and derivation state;
+- the local read state and the exported write state;
+- the contact and direction binding;
+- the authorized storage-manifest range;
+- whether the grant is a stream or single-box grant;
+- issue, recovery, replacement, and closure status.
+
+A crash cannot produce two different grants for one persisted stream
+generation. An exported write cap is secret bearer material and receives the
+same transfer protection as a contact voucher.
+
+### 6.3 Capability evolution
+
+After deriving one box, a conforming implementation stages the next index and
+evolving KDF state, then securely deletes the retired per-box secret after the
+required data record and recovery tombstone are committed locally.
+
+The active profile sets a maximum box count far below unsigned 64-bit wrap and
+a maximum stream lifetime. Stream renewal creates a new independent root and
+is authenticated through the existing FOG-MESSAGING ratchet.
+
+FOG MUST NOT claim capability forward secrecy or backward unlinkability until
+the exact construction, state serialization, deletion behavior, and backup
+rules have been reviewed.
+
+### 6.4 Revocation and loss
+
+A copied read or write capability cannot be remotely revoked. Revocation
+means abandoning the stream, distributing a fresh stream grant only to
+remaining authorized parties, and allowing old records to expire or be
+tombstoned where safe.
+
+Lost or rolled-back stream state cannot be reconstructed from online replicas.
+A stale Composer restore places the affected stream in `RECOVERY_REQUIRED`.
+It MUST NOT resume the old index or probe successive boxes in an attempt to
+guess live state.
+
+### 6.5 One-time drops
+
+`fog-drop` requires a genuinely attenuated single-box writer grant. The grant
+must expose only the signing and encryption authority for one exact box and
+must not contain a future stream derivation state.
+
+The BACAP/Pigeonhole candidate is not activated for one-time drops until a
+reviewed upstream or separately reviewed attenuation method supplies this
+property. Exporting an ordinary unbounded BACAP write cap and merely asking a
+sender to use it once is not a one-time capability.
+
+## 7. Storage Replica Manifest
+
+### 7.1 Purpose
+
+Final-shard selection must not change because ordinary PKI epochs add, remove,
+or reorder descriptors while stored data remains live. FOG therefore uses one
+immutable `StorageReplicaManifest` for each storage epoch.
+
+The current, previous, and announced next manifests are carried as complete
+authority-authenticated objects by FOG-PKI consensus according to their
+activation and retention windows. Consumers MUST NOT merge replica lists from
+different manifests.
+
+### 7.2 Canonical object
+
+The public object uses `FOG-PKI-CBOR-1` and has this ordered body:
+
+```text
+[
+ network_id,
+ storage_manifest_version,
+ storage_epoch,
+ storage_profile_id,
+ geometry_compatibility_id,
+ valid_from,
+ fresh_until,
+ valid_until,
+ acceptance_window_id,
+ retention_profile_id,
+ cover_profile_id,
+ shard_function_id,
+ final_replica_count,
+ intermediate_replica_count,
+ minimum_replica_count,
+ ordered_replica_records,
+ previous_storage_manifest_hash
+]
+```
+
+Each `ordered_replica_records` entry contains:
+
+```text
+[
+ replica_node_id,
+ node_descriptor_hash,
+ operator_id,
+ family_ids,
+ infrastructure_group_ids,
+ replica_envelope_algorithm_id,
+ replica_envelope_key_id,
+ replica_envelope_public_key,
+ replica_receipt_algorithm_id,
+ replica_receipt_key_id,
+ replica_receipt_public_key,
+ supported_storage_profile_ids
+]
+```
+
+Replica records are sorted by complete `replica_node_id`, duplicate-free, and
+byte-identical for every authority signer. One node, operator, prohibited
+family, or prohibited infrastructure group MUST NOT occupy more than one of
+the four positions used by one claim-bearing operation.
+
+The body is wrapped as one registered `FOG-PKI-CBOR-1` signed object and one
+authenticated envelope containing independent authority signatures over
+identical canonical bytes. It is valid only with the active FOG-PKI quorum.
+
+### 7.3 Sign-once and transition
+
+Authorities persist the manifest hash for a storage epoch before releasing a
+signature. Signing two different manifests for one storage epoch is
+equivocation evidence.
+
+The next manifest is announced early enough that every replica can generate
+its purpose-separated next envelope and receipt keys and every offline
+Composer can import it. The exact overlap is profile-defined. Failure to
+produce a valid manifest stops new storage work for that epoch.
+
+Ordinary node removal does not rewrite an active storage manifest. Emergency
+revocation can stop new operations to a compromised replica, but cannot
+silently remap live boxes. Availability loss and a new manifest are handled as
+an explicit storage transition.
+
+## 8. Storage Profile Registry and Epochs
+
+### 8.1 Immutable profile
+
+Every active storage profile maps one non-zero unsigned 32-bit identifier to
+exact dependencies and behavior. An identifier MUST NOT be reused after any
+primitive, field, size, shard rule, epoch rule, limit, response, or failure
+behavior changes.
+
+An exact profile record includes at least:
+
+```text
+[
+ storage_profile_id,
+ capability_specification_and_revision,
+ capability_primitive_suite_id,
+ capability_encoding_id,
+ box_id_length,
+ box_signature_length,
+ box_payload_aead_id,
+ replica_envelope_specification_and_revision,
+ replica_envelope_suite_id,
+ replica_receipt_signature_suite_id,
+ envelope_hash_id,
+ shard_function_id,
+ courier_envelope_format_id,
+ courier_reply_format_id,
+ replica_request_format_id,
+ replica_response_format_id,
+ final_replica_count,
+ intermediate_replica_count,
+ minimum_replica_count,
+ storage_epoch_schedule_id,
+ key_acceptance_window_id,
+ retention_profile_id,
+ geometry_compatibility_id,
+ box_plaintext_capacity,
+ courier_dedup_retention,
+ request_generation_limit,
+ polling_profile_id,
+ cover_profile_id,
+ resource_limit_profile_id,
+ conformance_vector_set_id
+]
+```
+
+The accepted consensus authorizes exact numeric profile IDs. Operators do not
+select primitives, shard counts, geometry, retention, or parser behavior.
+Incomplete candidates receive no numeric ID.
+
+### 8.2 Storage epoch
+
+The storage epoch is distinct from the FOG-PKI network epoch. Its duration,
+origin, key-generation deadline, acceptance overlap, record namespaces, and
+garbage-collection boundary are fixed by the authenticated storage profile.
+
+The candidate acceptance window is structurally equivalent to previous,
+current, and next storage envelope keys around a boundary. Exact durations are
+not selected in this draft. A request outside the accepted manifest and key
+window is rejected without attempting every historical key.
+
+Replica clocks use the same explicit uncertainty model as FOG-PKI. A request,
+courier, replica peer, HTTP header, or operator cannot supply authoritative
+time or extend a record lifetime.
+
+### 8.3 Retained manifests and keys
+
+A role retains exactly the manifest, public verification material, and private
+role keys needed for the profile's bounded previous, current, next, and drain
+windows. It rejects older work and deletes expired private envelope and
+receipt keys after all accepted request and response lifetimes end.
+
+The Composer retains public old-manifest material only while a live record may
+still be read or a receipt may still be verified. A long-offline Composer must
+import an authenticated manifest history, not accept a relay-provided current
+replica set on trust.
+
+## 9. Fixed Formats and Geometry
+
+### 9.1 Encoding rules
+
+Online storage operations use fixed binary structures, not CBOR, maps,
+compression, generic RPC, or packet autodetection. Every active profile gives
+one exact length for each structure and one exact FOG-WIRE record count.
+
+All read, write, tombstone, miss, hit, conflict, accepted, result, and cover
+bodies have equal outer geometry within the active traffic class. Fields that
+are absent for one semantic operation are zero before authenticated
+encryption.
+
+### 9.2 Courier envelope prefix
+
+The fixed `CourierEnvelope` begins with this exact 192-byte prefix:
+
+```text
+offset length field
+0 2 storage_format_version
+2 1 envelope_kind
+3 1 flags
+4 4 storage_profile_id
+8 8 storage_epoch
+16 32 storage_manifest_hash
+48 32 intermediate_replica_id_0
+80 32 intermediate_replica_id_1
+112 32 replica_envelope_key_id_0
+144 32 replica_envelope_key_id_1
+176 1 preferred_response_slot
+177 1 response_slot_count
+178 14 reserved
+```
+
+`envelope_kind` is `OPERATION`, `flags` is zero, `response_slot_count` is 2,
+and `preferred_response_slot` is 0 or 1. The two intermediate IDs are distinct
+and in canonical ascending order; preference is an independent CSPRNG choice
+and does not reorder them.
+
+The prefix is followed by profile-fixed areas:
+
+```text
+client_ephemeral_public_key[P]
+intermediate_dek_0[D]
+intermediate_dek_1[D]
+encrypted_inner_request[Q]
+zero_padding[Z]
+```
+
+The complete body, including `Z`, is exactly the compatible KEMSphinx
+`user_forward_payload_length`. The multi-recipient envelope authenticates the
+prefix and encrypts the complete fixed inner request to either intermediate
+replica. The courier cannot decrypt it.
+
+The courier request hash is:
+
+```text
+envelope_hash = HASH(
+ storage_profile_domain || complete_fixed_CourierEnvelope
+)
+```
+
+The profile fixes the hash and domain. The hash is a short-lived courier-local
+deduplication handle, not a message ID, box ID, account, capability, or
+cross-generation identifier.
+
+### 9.3 Inner replica request
+
+After envelope decapsulation, an intermediate obtains one fixed
+`ReplicaInnerRequest`:
+
+```text
+[
+ inner_format_version,
+ operation_kind,
+ flags,
+ storage_profile_id,
+ storage_epoch,
+ storage_manifest_hash,
+ operation_nonce[32],
+ box_id[B],
+ box_signature[S],
+ fixed_box_payload[X],
+ zero_padding
+]
+```
+
+`operation_kind` is `READ`, `WRITE_DATA`, or `WRITE_TOMBSTONE`. For READ, the
+signature and payload areas are zero. For WRITE_DATA, they contain the exact
+capability-authenticated record. For WRITE_TOMBSTONE, the signature
+authenticates the candidate construction's canonical empty payload and the
+fixed payload area is zero.
+
+The operation nonce contains 256 CSPRNG bits and is unique per courier request
+generation. It is not a capability and does not replace box-record
+authentication.
+
+### 9.4 Courier reply
+
+Every anonymous reply begins with one exact 64-byte prefix:
+
+```text
+offset length field
+0 2 storage_reply_format_version
+2 1 reply_kind
+3 1 actual_response_slot
+4 4 storage_profile_id
+8 32 envelope_hash
+40 1 outer_status
+41 23 reserved
+```
+
+It is followed by one fixed opaque replica-response area `R` and zero padding
+to the compatible KEMSphinx reply capacity. `reply_kind` is `ACCEPTED`,
+`RESULT`, or `COARSE_REJECT`. ACCEPTED and COARSE_REJECT have a zero response
+area. RESULT contains one replica-encrypted aggregate response from an
+intermediate.
+
+The reply size, KEMSphinx route, and external schedule do not reveal the kind.
+The courier necessarily knows which coarse reply it constructed but does not
+learn the encrypted replica outcome.
+
+### 9.5 Replica commands
+
+FOG-WIRE command bodies are fixed by the same compatibility profile:
+
+- `REPLICA_REQUEST` carries one envelope hash and the fixed public-key,
+ encapsulation, and ciphertext fields required by one intermediate;
+- `REPLICA_RESPONSE` carries the envelope hash, response slot, and one fixed
+ client-encrypted aggregate reply;
+- `REPLICA_SYNC` carries one fixed `SHARD_OPERATION`, `SHARD_RESPONSE`, or
+ bounded repair body between storage replicas.
+
+Subtypes are authenticated inside their owning fixed body. FOG-WIRE context
+and command selection do not authorize a different storage profile.
+
+### 9.6 Geometry equations
+
+For a KEMSphinx forward capacity `U`:
+
+```text
+192 + P + (2 * D) + Q + Z = U
+```
+
+The encrypted inner capacity must satisfy:
+
+```text
+message_envelope_length
+ + capability_payload_overhead
+ + inner_request_overhead
+ + replica_envelope_overhead
+ <= Q
+```
+
+The compatible reply must hold one fixed box record, two final-replica
+receipts, aggregate framing, and response encryption. FOG-WIRE must hold the
+same objects in its declared record counts.
+
+No document may treat the calculated 4,096-byte KEMSphinx candidate user
+payload as the box or message capacity before a byte-exact geometry calculator
+proves every equation in both directions.
+
+## 10. Replica and Courier Selection
+
+### 10.1 Eligible set
+
+The Composer uses only the ordered replica records in the accepted manifest.
+Every selected replica must support the exact active storage, envelope,
+receipt, and FOG-WIRE profiles and have an unrevoked current endpoint in the
+accepted FOG-PKI consensus.
+
+A claim-bearing manifest has at least four storage replicas controlled by
+distinct operators and prohibited-family domains. Co-location or shared
+credentials invalidate the independence assumption even if node IDs differ.
+
+### 10.2 Final shard pair
+
+The profile's deterministic shard function scores every eligible replica from
+the exact manifest using a domain-separated hash over at least the manifest
+hash, replica storage identity, and box ID. The two lowest distinct scores are
+the final shard pair, with complete node ID as the deterministic tie breaker.
+
+The candidate deliberately adds FOG network, profile, and manifest domain
+binding to the Pigeonhole-derived two-shard selection. This is not byte-
+compatible with Katzenpost `Shard2` and requires independent analysis,
+byte-identical vectors, and a distinct immutable profile.
+
+Every Composer and replica computes the pair byte-identically. The courier is
+not given the box ID or pair.
+
+### 10.3 Intermediate pair
+
+The Composer excludes the final pair, then chooses two distinct intermediate
+replicas uniformly with its CSPRNG from the remaining eligible set. It rejects
+a choice that repeats a prohibited operator, family, or infrastructure domain
+across the courier and four storage positions when the active claim requires
+that diversity.
+
+At exactly four replicas, the two non-final replicas are the only valid
+intermediate set. At three or fewer, claim-bearing work stops. A local fixture
+may use a named functional-test profile that makes no intermediate/final
+unlinkability claim.
+
+### 10.4 Courier
+
+The Composer selects an eligible courier independently from the storage set
+under the authenticated route and diversity policy. One courier request
+generation remains pinned to that courier because its dedup cache holds the
+operation state.
+
+A bounded later generation MAY use another courier after the previous
+generation's lifetime and reply material expire. It keeps the same box record
+and normally the same intermediate pair to avoid progressively exposing the
+box to more storage roles. Exact failover and exposure limits belong to the
+retry profile.
+
+## 11. Write Processing
+
+### 11.1 Composer write transaction
+
+FOG-MESSAGING first supplies one already committed immutable
+`MessageEnvelope`. The storage writer then MUST:
+
+1. verify that no earlier box is still unresolved for the stream;
+2. clone the current write-capability state;
+3. derive one box ID, payload key, signing key, and next stream state;
+4. encrypt and authenticate the fixed message envelope as one data box;
+5. create the exact signed data record and a canonical signed recovery
+ tombstone for the same box;
+6. select the manifest, final pair, intermediate pair, courier, and envelope
+ keys under the accepted profiles;
+7. build one exact immutable `CourierEnvelope` request generation;
+8. atomically persist the next stream state, data record, tombstone, immutable
+ courier envelope, selection, retry state, and storage outbox status;
+9. erase retired per-box private material and discarded staged state;
+10. only after commit, make the KEMSphinx operation exportable.
+
+A crash before step 8 exports nothing. A crash after step 8 recovers the exact
+box and courier envelope without re-deriving the box or reusing a per-box key.
+
+Only one box write per stream is externally outstanding. Later application
+messages may queue locally but cannot skip an unresolved storage index.
+
+### 11.2 Courier dispatch
+
+After terminal KEMSphinx validation, the courier:
+
+1. strictly parses the fixed envelope and accepted manifest window;
+2. computes the envelope hash;
+3. checks the bounded dedup cache;
+4. on a cache miss, allocates one bounded state entry and dispatches exactly
+ one fixed request to each named intermediate replica;
+5. uses the current request's SURB for one scheduled ACCEPTED or cached RESULT
+ reply and does not retain the SURB;
+6. caches at most two fixed opaque replica responses until the dedup deadline.
+
+A cache hit never dispatches the request again. If a cached result is
+available, the courier can return it using the fresh SURB carried by the
+retransmission. Otherwise it returns ACCEPTED. All replies remain subject to
+the external schedule and one-response amplification bound.
+
+### 11.3 Intermediate processing
+
+Each intermediate replica:
+
+1. authenticates the courier through FOG-WIRE;
+2. validates exact profile, manifest, key ID, epoch, ciphertext, and limits;
+3. decapsulates and authenticates the complete inner request;
+4. recomputes and validates the two final replicas;
+5. dispatches the exact operation to both final replicas through fixed
+ `REPLICA_SYNC` shard-operation bodies;
+6. collects bounded final receipts without treating a link ACK as a commit;
+7. builds one fixed aggregate response encrypted for the Composer ephemeral
+ key;
+8. sends the opaque response to the courier and erases request secrets and
+ transient box state after the retry window.
+
+It performs no application parsing and never retains a stream capability.
+
+### 11.4 Final write transaction
+
+A final replica verifies the manifest, epoch, operation nonce, box ID, box
+signature, record size, and storage quota before mutation. It then applies one
+atomic transaction:
+
+- empty plus valid data: insert the complete record;
+- same exact data: idempotent success;
+- different data at the same box: conflict, no overwrite;
+- any state plus valid tombstone: store the tombstone and delete live data;
+- tombstone plus data: tombstone wins, reject resurrection;
+- same valid tombstone: idempotent success.
+
+The replica durably commits database and required local journal state before
+signing a commit receipt. A transport ACK, queued write, in-memory update, or
+unflushed batch is not a commit receipt.
+
+### 11.5 Writer completion
+
+The Composer verifies receipts under the exact two final-replica receipt keys
+from the manifest. `REPLICA_QUORUM_COMMITTED` requires matching durable
+receipts from both final replicas for the same manifest, epoch, nonce, box ID,
+record digest, and result.
+
+One receipt is degraded evidence, not quorum. A courier ACCEPTED reply is not
+replica evidence. The writer retains and retries the immutable box until:
+
+- two matching commit receipts arrive;
+- the receiving Composer's later message-level commit ACK proves successful
+ retrieval;
+- a valid recovery tombstone is committed to both replicas; or
+- the operation enters explicit `UNCERTAIN` or `RECOVERY_REQUIRED` state.
+
+The next storage box is not exported while the current box remains unresolved.
+
+## 12. Read, Empty, and Tombstone Processing
+
+### 12.1 Read query
+
+The reader clones but does not advance its current capability state, derives
+the expected box ID, selects the manifest and roles, generates a fresh
+operation nonce, and atomically persists one immutable read request generation
+before export.
+
+Retransmission within that generation uses the same courier envelope and fresh
+KEMSphinx and reply material. A later poll after a terminal result uses a new
+operation nonce and new courier envelope but derives the same box ID until the
+stream advances.
+
+### 12.2 Final read response
+
+Each final replica atomically reads one box and returns one fixed response:
+
+- `DATA`: complete record and its digest;
+- `TOMBSTONE`: complete signed tombstone and its digest;
+- `MISS`: no record observed for the box in that namespace;
+- `CONFLICT` or coarse local failure where internal consistency is broken.
+
+The final replica signs a receipt over the network, storage profile, manifest,
+epoch, operation nonce, box ID, result code, and record digest. MISS uses the
+canonical empty digest. FOG-WIRE protects the receipt between the final and
+intermediate replica. The intermediate then places it in the fixed aggregate
+response encrypted toward the Composer, so the courier cannot inspect it.
+
+A receipt authenticates what one replica reported. It does not make a
+malicious replica honest or make absence permanent.
+
+### 12.3 Aggregate result
+
+An intermediate aggregate contains two final-replica receipts and at most one
+complete fixed box record. The record digest must match both receipts before
+the Composer treats the final replicas as converged.
+
+The Composer handles results as follows:
+
+- matching DATA receipts: verify box signature, decrypt, validate fixed
+ payload and pass it to the owning upper protocol transaction;
+- matching TOMBSTONE receipts: verify the writer signature, atomically advance
+ the read capability, and emit no message content;
+- matching MISS receipts: report one empty poll locally and do not advance;
+- one DATA and one MISS: treat as replication lag and retry under schedule;
+- one TOMBSTONE and one older DATA: wait for tombstone convergence;
+- different valid data digests: freeze the stream as `STORAGE_CONFLICT`;
+- missing, invalid, wrong-manifest, wrong-nonce, or wrong-box receipt: discard
+ without advancement.
+
+### 12.4 Cross-layer receive commit
+
+For a DATA result, storage payload acceptance and FOG-MESSAGING acceptance are
+one Composer transaction. The implementation stages the next read-capability
+state, storage dedup state, message authentication, ratchet state, reassembly,
+inbox, and message ACK state, then commits them together before rendering.
+
+If the box is authentically written but contains an invalid FOG-MESSAGING
+object, the Composer atomically records a bounded poisoned-slot marker and MAY
+advance the storage stream without advancing the message ratchet. It sends no
+automatic error oracle. This behavior is permitted only for a box whose writer
+authentication is valid, because otherwise an online attacker could skip
+stream positions.
+
+The exact malicious-contact UI and quarantine retention belong to
+FOG-COMPOSER, but their count and byte limits belong to the storage profile.
+
+### 12.5 Meaning of empty
+
+MISS is an expected asynchronous state. It can arise because the writer has
+not written, replication is delayed, a replica is malicious, a request reached
+the wrong retained epoch, or data expired.
+
+The reader polls again only under its authenticated retrieval schedule. It
+does not immediately retry on MISS, advance to the next box, switch to a
+direct replica, or send a message-level acknowledgment.
+
+## 13. Courier Deduplication, Retry, and Reply State
+
+### 13.1 Courier cache
+
+One courier cache entry contains only:
+
+```text
+[
+ envelope_hash,
+ storage_profile_id,
+ storage_epoch,
+ storage_manifest_hash,
+ created_monotonic_time,
+ intermediate_replica_ids[2],
+ dispatch_state[2],
+ opaque_response_slots[2],
+ terminal_deadline
+]
+```
+
+It contains no SURB, capability, box ID, operation kind, final pair, message
+identifier, user identifier, or application state. Cache memory and total
+entries are bounded globally and per authenticated replica relationship.
+
+The cache MAY be volatile because final operations are idempotent. A courier
+restart may redispatch an exact request, but cannot change the box record.
+Persistent cache, if used, has a dedicated sealing key and the same strict
+expiry.
+
+### 13.2 Request generation
+
+The Composer persists these minimum states:
+
+- `READY`: immutable generation committed but not exported;
+- `IN_FLIGHT`: exported and eligible for exact retransmission;
+- `COURIER_ACCEPTED`: courier accepted bounded work, durability unknown;
+- `REPLICA_QUORUM_COMMITTED`: two matching final receipts verified;
+- `DEGRADED`: only one matching final receipt or replica unavailable;
+- `EMPTY`: one completed read poll returned matching MISS receipts;
+- `TOMBSTONED`: matching valid tombstone receipts committed;
+- `CONFLICT`: incompatible authenticated final states;
+- `EXPIRED`: request-generation retry limit reached;
+- `UNCERTAIN`: local durability or remote outcome cannot be resolved;
+- `CANCELLED`: local cancellation before a security-critical transition.
+
+The message outbox remains separate. Storage quorum does not set a message to
+ACKED, and message ACK may safely terminate storage retry after proving the
+receiver committed the message.
+
+### 13.3 Retransmission
+
+Within one request generation, the Composer reuses exact `CourierEnvelope`
+bytes and pins the courier and intermediate pair. Every transmission creates a
+fresh packet, SURB, private reply token, route, entry material, and transfer
+bundle identifier.
+
+The profile sets maximum attempts, maximum generation age, jitter, backoff,
+cache retention, result polling, and maximum later generations. No retry is
+immediate or seeded from a box, envelope, contact, or message identifier.
+
+A later generation builds a new inner request around the same immutable box
+record and operation kind, using a fresh operation nonce and ephemeral
+envelope key. It starts only after old reply
+material and the previous courier cache window end, and it remains subject to
+the fixed exposure budget.
+
+### 13.4 Reply material
+
+The courier never stores a SURB for later use. It consumes the fresh SURB from
+the current KEMSphinx request for at most one fixed reply. If no result is ready
+it returns ACCEPTED; the Composer later supplies a new single-use SURB by
+retransmitting the same courier envelope.
+
+No result causes a direct second reply, and no storage ACK causes an ACK of its
+own. This keeps amplification at one anonymous reply per accepted request.
+
+## 14. Replica Receipts and Consistency
+
+### 14.1 Receipt body
+
+A final-replica receipt is a profile-fixed canonical object whose signed body
+contains:
+
+```text
+[
+ receipt_format_version,
+ network_id,
+ storage_profile_id,
+ storage_manifest_hash,
+ storage_epoch,
+ final_replica_id,
+ replica_receipt_key_id,
+ operation_nonce,
+ box_id,
+ operation_kind,
+ result_code,
+ record_digest
+]
+```
+
+The signature suite is fixed by the storage profile and key record. A result
+cannot name or negotiate its verifier. Receipt verification occurs only after
+the enclosing replica response authenticates and parses.
+
+Receipts are sensitive metadata because they contain box IDs. They are visible
+only to the processing storage replicas, then remain inside client-encrypted
+replies and Composer state. They MUST NOT be published as generic monitoring
+or transparency evidence.
+
+### 14.2 Durability model
+
+The initial structural profile has two final replicas and requires two
+matching receipts for ordinary write quorum or read convergence. It does not
+claim Byzantine consensus, linearizability, permanent durability, or global
+read-after-write ordering.
+
+A malicious final replica can sign false state, withhold work, delete data, or
+equivocate. Two independent receipts make the responsible identities locally
+detectable but do not restore deleted data. A malicious intermediate can
+withhold or reorder receipts but cannot forge a valid final receipt under the
+selected signature assumption.
+
+### 14.3 Conflicts and tombstone precedence
+
+Two different valid data records for one box indicate writer-state cloning,
+malicious writer behavior, or an implementation failure. Replicas preserve
+first-write-wins locally, and the Composer freezes on cross-replica divergence.
+
+A valid tombstone has permanent precedence within its storage-epoch namespace.
+Repair always propagates tombstone over data and never propagates data over a
+tombstone.
+
+## 15. Retention, Tombstones, and Garbage Collection
+
+### 15.1 Record retention
+
+Each record belongs to one storage-epoch namespace and receives its expiry
+only from the authenticated manifest and retention profile. A writer cannot
+request longer retention, and a replica cannot selectively extend one user's
+record.
+
+The active profile publishes the minimum and maximum retrieval window in
+ordinary time units and storage epochs. Public documentation MUST explain that
+an offline recipient who does not retrieve within that window can lose data.
+
+The candidate evaluates the Pigeonhole previous-and-current epoch retention
+shape, but no duration is selected until offline-usage, capacity, abuse, and
+cost simulations are complete.
+
+### 15.2 Tombstone creation
+
+The writer creates a canonical signed empty record. It is externally the same
+size class as read and data operations. The courier cannot distinguish it, but
+the replicas necessarily learn that a valid box is being tombstoned.
+
+A recovery tombstone is generated and stored locally with every data box before
+the per-box signing key is erased. It may be exported only under explicit
+abandon, recovery, user deletion, or profile policy.
+
+Routine successful delivery SHOULD normally rely on bounded natural expiry
+rather than an immediate tombstone correlated with recipient activity. If
+automatic tombstoning is enabled, its minimum hold, random delay, and cover
+schedule are authenticated profile parameters.
+
+### 15.3 Replica tombstone state
+
+After durable tombstone commit, a replica deletes the live ciphertext and
+retains the minimum authenticated tombstone record needed to reject
+resurrection. That record remains until the complete namespace expires.
+
+Garbage collection MUST delete data and tombstones by deterministic epoch
+policy, not access recency, contact activity, request frequency, or operator
+preference. It runs under bounded IO and cannot block wire processing without
+backpressure.
+
+### 15.4 Deletion limits
+
+A tombstone is not proof that every historical copy vanished. A recipient may
+already hold plaintext; an attacker may have copied ciphertext; storage media,
+journals, snapshots, and backups may retain blocks until their documented
+destruction window.
+
+Replica backups use separate encryption keys and bounded retention. Restore
+MUST NOT resurrect expired data or replace a tombstone with older live data.
+The operator documents the maximum backup-deletion delay and tests restore
+against tombstone and expiry state.
+
+### 15.5 Expired-gap recovery
+
+Because MISS never advances a reader, a box that expires before retrieval can
+block every later box in that stream. If the writer still has an unacknowledged
+immutable data record, it MAY reemit that exact record into a currently valid
+storage-epoch namespace under a new bounded request generation. If the writer
+has abandoned the data, it reemits the precomputed signed tombstone instead.
+
+The reader advances only after a converged authenticated DATA or TOMBSTONE
+result. Cross-epoch reemission may reveal the same box to additional replicas
+or link epochs and therefore has a profile exposure limit and simulation gate.
+If neither the writer nor a fresh authenticated recovery session is available,
+the reader cannot safely skip the gap.
+
+## 16. Replication, Repair, and Manifest Transition
+
+### 16.1 Normal replication
+
+Both intermediate replicas dispatch the authenticated operation to the same
+two deterministic final replicas. Final writes are idempotent, so duplicate
+paths cannot create duplicate boxes or change first-write-wins behavior.
+
+The profile fixes the maximum fan-out. One courier request creates at most two
+courier-to-intermediate requests, four intermediate-to-final shard operations,
+bounded responses, and one anonymous client reply. Implementations MUST NOT
+increase fan-out after failure.
+
+### 16.2 Repair
+
+`REPLICA_SYNC` supports bounded repair only between the two final replicas for
+one manifest and retained epoch. A repair body carries one complete
+authenticated box record or tombstone and the evidence required by the
+profile. The receiving replica independently verifies the box signature,
+manifest, epoch, digest, and tombstone precedence before commit.
+
+Repair traffic uses fixed FOG-WIRE shapes and the authenticated store-to-store
+schedule. It MUST NOT expose an unbounded database listing, stream sequence,
+capability root, or arbitrary range query.
+
+### 16.3 Replica unavailability
+
+One unavailable final produces degraded durability and no ordinary quorum.
+The operation retries under schedule but does not substitute an arbitrary
+third final, because that would change deterministic location and reveal more
+replicas.
+
+If a manifest cannot meet its deployment assumptions, new work stops or uses
+an already authorized lower-claim functional profile. Existing data remains
+bound to the old manifest until expiry.
+
+### 16.4 Manifest transition
+
+A new storage epoch creates a new immutable manifest and new replica envelope
+and receipt keys. Old and new manifests coexist only for the explicit read,
+retry, key, and drain windows.
+
+FOG does not silently migrate live boxes to a new final set. A writer that
+needs a longer-lived logical message re-emits it through a new authenticated
+storage operation or renewed stream according to the upper protocol. Cross-
+epoch re-emission remains bounded and may expose linkability at replicas, so it
+requires explicit simulation and profile rules.
+
+## 17. Cover, Empty Reads, and Failure Privacy
+
+### 17.1 Traffic scheduling
+
+Fixed bytes do not hide record counts or time. Any claim that reads, writes,
+misses, or tombstones are externally indistinguishable requires:
+
+- Composer operations entering the same authenticated client schedule;
+- KEMSphinx packets and replies using one geometry;
+- courier-to-replica and replica-to-replica links using fixed-throughput or
+ independently scheduled fixed slots with valid cover;
+- retry and result polling independent of application type;
+- overload and shutdown behavior included in the simulation.
+
+Exact rates and distributions remain cover-profile selections. Operators MUST
+NOT tune them independently in a claim-bearing deployment.
+
+### 17.2 Role-local distinguishability
+
+The courier can distinguish ACCEPTED from a cached opaque RESULT but cannot
+decrypt the result. Intermediate and final replicas necessarily distinguish
+operation types after envelope decryption. FOG claims only the information
+exposure stated in Section 3, not perfect role-local indistinguishability.
+
+### 17.3 Repeated empty polling
+
+Repeated reads of one not-yet-written box reveal the same box ID to its final
+replicas. Changing KEMSphinx routes, couriers, envelopes, or intermediates does
+not remove that final-replica link.
+
+The retrieval profile therefore bounds polling frequency, uses cover traffic,
+avoids immediate reaction to a write or MISS, and includes this leakage in
+long-term intersection simulation. FOG makes no unconditional claim that an
+honest-but-curious final replica cannot recognize repeat polls.
+
+### 17.4 Failure classes
+
+Online remote failures are coarse:
+
+- malformed or unauthorized envelope: uniform drop or fixed COARSE_REJECT;
+- accepted bounded work: fixed ACCEPTED;
+- available opaque result: fixed RESULT;
+- overload or timeout: fixed coarse outcome under the cover schedule.
+
+Detailed DATA, TOMBSTONE, MISS, conflict, database, quota, receipt, and
+replication results remain inside Composer-encrypted responses where possible.
+No error is larger than the request, and one request produces at most one
+anonymous reply.
+
+## 18. Resource Limits and Storage DoS
+
+Capability-based addressing is not a complete admission system. An attacker
+can create unlimited self-owned capabilities, valid signatures, boxes, reads,
+or tombstones. Random box IDs prevent guessing another stream but do not
+prevent storage exhaustion.
+
+Every active profile MUST set lower limits within explicit version maxima for:
+
+- accepted envelope bytes and cryptographic work;
+- courier cache entries, bytes, generations, dispatches, and lifetime;
+- intermediate in-flight requests, final fan-out, retries, and response bytes;
+- final records, bytes, writes, reads, tombstones, receipts, and repair work;
+- per-peer FOG-WIRE queues and connections;
+- per-manifest and per-storage-epoch total capacity;
+- Composer streams, pending boxes, empty polls, poisoned slots, and retained
+ receipts;
+- backup size, journal size, garbage-collection work, and restore input;
+- cover backlog and degraded-mode thresholds.
+
+At minimum, the first structural profile has:
+
+- exactly two intermediates and two finals per request;
+- no more than one anonymous reply per request;
+- one unresolved external box per stream;
+- no operator-controlled variable replication factor;
+- no recursive operation, generic batch, arbitrary range, or server-side
+ capability traversal;
+- no CopyCommand or AllOrNothing operation;
+- no requester-selected expiry or replica list outside the manifest.
+
+Authentication and size validation occur before database mutation. Allocation
+is bounded before public-key work where the format permits. Signature-valid
+new writes are still subject to global epoch capacity and overload policy.
+
+When full, a replica preserves already committed records and tombstones until
+their policy expiry and rejects new allocation with a coarse fixed response.
+It MUST NOT evict according to access recency, user activity, application type,
+or payment outside a separately reviewed admission protocol.
+
+Safe anonymous admission and fair rate control remain open. Until resolved,
+FOG does not claim resistance to a determined distributed storage-flooding
+adversary.
+
+## 19. Profile and State Transitions
+
+### 19.1 Stream states
+
+The minimum Composer stream states are:
+
+- `ISSUED`: reader state persisted and writer grant ready for export;
+- `ACTIVE`: one writer and one reader state are valid;
+- `WRITE_PENDING`: one immutable box and request generation are outstanding;
+- `READ_POLLING`: the current box has a persisted read request generation;
+- `RENEWING`: a new stream generation is authenticated through messaging;
+- `STORAGE_CONFLICT`: replicas returned incompatible authenticated state;
+- `FROZEN_CAPABILITY_CHANGE`: an unexpected grant or state change is present;
+- `RECOVERY_REQUIRED`: rollback, cloning, loss, or compromise prevents reuse;
+- `CLOSED`: no new boxes may be created.
+
+State files are not an API. A transition occurs only through the atomic
+Composer operations defined here and in FOG-MESSAGING.
+
+### 19.2 Storage profile transition
+
+A contact switches storage profiles only through an authenticated
+FOG-MESSAGING control transition that binds the exact new profile, stream
+generation, capabilities, first index, and manifest activation.
+
+Old and new streams remain separate. There is no profile trial, mixed
+capability derivation, dual decryption of one box, or fallback after failure.
+The old stream drains only through its previously authorized profile and
+retention window.
+
+### 19.3 Compromise
+
+Compromise of a write cap permits reading where derivable, arbitrary future
+writes, conflicting writes, and tombstones for that stream. Compromise of a
+read cap permits future location derivation and decryption but not valid writes
+under the selected construction.
+
+Response requires stopping the stream, replacing the Composer or capability
+state, distributing a new stream through an authenticated contact session,
+and allowing old data to expire. Rotation to the next box does not remove an
+attacker who copied the root capability.
+
+## 20. Candidate BACAP and Pigeonhole Integration
+
+### 20.1 Candidate definition
+
+`FOG-STORAGE-CANDIDATE-BACAP-PIGEONHOLE-1` evaluates:
+
+- the maintained BACAP implementation and its deterministic blinded Ed25519
+ box sequence, evolving KDF state, signatures, and authenticated payload
+ encryption;
+- the maintained Pigeonhole single-box courier and scattered-replica flow;
+- two deterministic final replicas, two disjoint random intermediates, and at
+ least four eligible replicas;
+- one fixed multi-recipient envelope for the two intermediates;
+- identical courier-envelope retransmission with fresh Sphinx-family packet
+ and SURB material;
+- FOG storage manifests, final-replica receipts, fixed binary formats, atomic
+ Composer state, and FOG-WIRE commands defined here.
+
+The candidate does not adopt the Katzenpost client daemon, PKI epochs,
+transport wire bytes, service discovery, Sphinx geometry, or operator
+configuration as FOG runtime dependencies.
+
+### 20.2 Deliberate exclusions and deviations
+
+The initial FOG candidate excludes Pigeonhole CopyCommand and AllOrNothing
+streams because they give the courier a serialized write capability and make
+it traverse capability-derived boxes. That behavior conflicts with the FOG
+courier boundary.
+
+The candidate adds final-replica receipts so the offline Composer can
+distinguish courier acceptance from evidence of final durable commit. This is
+a FOG protocol extension requiring its own cryptographic and metadata review.
+
+FOG-MESSAGING fragmentation remains above storage. Multiple fragments are not
+atomically visible at replicas; the receiving Composer releases content only
+after authenticated complete reassembly.
+
+### 20.3 Claims deliberately withheld
+
+The candidate does not yet establish:
+
+- direct Katzenpost Pigeonhole interoperability;
+- quantum-resistant box authenticity, capability security, or complete
+ storage confidentiality;
+- unlinkability if the courier and relevant replicas collude;
+- unlinkability of repeated reads to one empty box at a final replica;
+- deletion of every backup or adversarial copy;
+- Byzantine consistency, guaranteed delivery, or permanent durability;
+- DoS resistance or anonymous fair admission;
+- safe one-box attenuation for `fog-drop`;
+- compatibility with the calculated 4,096-byte KEMSphinx payload;
+- implementation, constant-time, side-channel, or secure-deletion safety.
+
+### 20.4 Activation gates
+
+Before promotion to an active numeric profile, FOG MUST freeze and verify:
+
+1. exact BACAP, Pigeonhole, KDF, signature, AEAD, hash, envelope, and receipt
+ revisions and source commits;
+2. whether the reviewed capability semantics and security analysis cover the
+ exact exported writer and reader state used by FOG;
+3. byte-exact capability, box, courier, replica, receipt, and manifest
+ serialization;
+4. complete forward and reply geometry against one exact KEMSphinx and
+ FOG-WIRE profile;
+5. transcript, network, profile, manifest, epoch, box, and operation-nonce
+ domain binding without changing upstream primitives silently;
+6. deterministic shard and intermediate-selection vectors;
+7. crash, rollback, duplicate, conflict, tombstone, repair, expiry, backup,
+ and manifest-transition behavior;
+8. loss, delay, replay, empty polling, courier restart, and replica failure;
+9. CPU, memory, disk, bandwidth, amplification, flood, and GC limits;
+10. implementation maturity, dependency licensing, side-channel behavior, and
+ secret deletion;
+11. independent cryptographic and implementation review before public claims.
+
+A required change to BACAP derivation, signing, or encryption creates a
+separately identified candidate rather than an undocumented FOG variant.
+
+## 21. Key and Secret Lifecycle
+
+| Material | Owner | Persistence | Required destruction or transition |
+| --- | --- | --- | --- |
+| Stream write root and evolving state | one writer Composer | encrypted mutable state, never online | replace by new stream on compromise, clone, rollback, or profile transition |
+| Stream read root and evolving state | one reader Composer; writer MAY derive under candidate | encrypted mutable state, never online | replace by new stream on compromise, clone, rollback, or profile transition |
+| Per-box signing and payload keys | Composer transaction | transaction only | erase after data record, recovery tombstone, next state, and outbox commit |
+| Immutable signed data record | writer Composer and final replicas | bounded outbox and storage-epoch state | remove after message ACK and recovery margin locally; GC by replica retention |
+| Signed recovery tombstone | writer Composer, final replicas only after use | encrypted local outbox until resolution | erase locally after terminal retention; retain at replica to namespace expiry |
+| Operation nonce | writer or reader Composer | one courier request generation | erase after generation and receipt retention |
+| Composer envelope ephemeral private key | requesting Composer | one request generation | erase after all expected replies and retry retention end |
+| Intermediate DEKs and shared secrets | Composer and addressed intermediate transaction | immutable public encapsulation plus transient secret | erase transient decapsulation and response secrets after bounded processing |
+| Replica envelope private key | one storage replica | previous, current, next storage-key windows only | erase after accepted request and response drain ends |
+| Replica receipt private key | one final replica | one storage-manifest key period | stop signing at retirement; erase after receipt verification drain |
+| Courier envelope hash and opaque responses | one courier | bounded dedup cache only | expire at courier dedup deadline; never back up by default |
+| Intermediate dispatch and aggregate state | one intermediate replica | bounded transient state | erase after response and retry window |
+| Final box record or tombstone | two deterministic final replicas | bounded storage-epoch namespace | deterministic GC; tombstone blocks resurrection until namespace expiry |
+| FOG-WIRE Noise key | one online node | role-local profile lifetime | never reuse as envelope, receipt, box, or at-rest key |
+| Replica storage-at-rest key | one replica operator | deployment-specific protected storage | separate rotation and backup policy, no protocol authenticity claim |
+| Replica backup key | one replica recovery domain | separate from backup ciphertext and live store | rotate and destroy under bounded backup-retention policy |
+
+Capability roots, per-box secrets, box IDs, operation nonces, courier hashes,
+receipts, replica ciphertexts, stream indexes, message envelopes, contacts, and
+selection details MUST NOT enter logs, metrics, command arguments, crash
+reports, public evidence, or support bundles.
+
+## 22. Logging and Observability
+
+Couriers and replicas MAY export delayed, thresholded aggregate counts for
+capacity, coarse success, overload, expiry, corruption, and repair only when
+the observability profile proves that the aggregation cannot expose a small
+activity set.
+
+They MUST NOT export:
+
+- box IDs, envelope hashes, operation nonces, receipt digests, or signatures;
+- intermediate or final selection per request;
+- per-record timestamps, read frequency, miss streaks, or tombstone timing;
+- capability bytes, payloads, ciphertext samples, or decryption failures;
+- per-contact, per-stream, per-courier-request, or per-source histories;
+- fine-grained queue, connection, or storage-access event streams.
+
+Local debugging that enables any prohibited class places the node outside a
+claim-bearing profile and must be disabled by default in release builds.
+
+## 23. Conformance and Adversarial Tests
+
+Before the local PoC, FOG-STORAGE requires deterministic positive and negative
+tests for:
+
+- capability issue-before-export, one-writer enforcement, index advancement,
+ serialization, cloning detection, and stale restore;
+- exact 192-byte courier prefix and 64-byte reply prefix;
+- every fixed body, padding byte, reserved bit, operation, and result;
+- manifest canonical encoding, authority signatures, sign-once state,
+ chaining, membership, key, diversity, and transition checks;
+- shard selection and intermediate exclusion across complete vector sets;
+- complete forward and reply geometry calculations;
+- Composer crash before and after write-state, record, tombstone, envelope,
+ and outbox commit;
+- reader crash before and after the combined storage and messaging commit;
+- exact request retransmission with fresh KEMSphinx and SURB material;
+- courier cache hit, miss, expiry, corruption, restart, and overload;
+- courier behavior without storing a SURB;
+- final empty insert, exact duplicate, conflicting data, tombstone overwrite,
+ tombstone duplicate, and data-after-tombstone rejection;
+- two matching receipts, one missing receipt, invalid receipt, wrong nonce,
+ wrong epoch, wrong manifest, equivocation, and conflicting digests;
+- DATA, TOMBSTONE, MISS, replication lag, poisoned message, and stream freeze;
+- replica loss, repair, manifest change, key overlap, expiry, GC, backup
+ restore, and non-resurrection;
+- fixed read, write, tombstone, hit, miss, retry, error, and cover geometry;
+- request and response amplification bounds;
+- malicious capability-holder CPU, memory, disk, queue, receipt, polling, and
+ notification exhaustion;
+- absence of prohibited values from logs, metrics, crashes, and support data;
+- candidate upstream vectors plus FOG-specific integration vectors.
+
+Testing MUST include parser fuzzing, property tests, transaction fault
+injection, simulated power loss, disk-full and partial-write faults, clock
+uncertainty, race detection, load and flood testing, cross-implementation
+vectors, and restore exercises.
+
+## 24. Threat and Architecture Traceability
+
+| Requirement | Primary controls |
+| --- | --- |
+| `ARC-002` | the networkless Composer owns capabilities, box derivation, final verification, and index advancement |
+| `ARC-003` | all client storage work traverses entry, every mix layer, courier, and replicas |
+| `ARC-004` | box, envelope, KEMSphinx, and Noise protections use separate protocols and keys |
+| `ARC-006` | fixed geometry and scheduling classes do not identify native applications |
+| `ARC-007` | stream, box, envelope, receipt, wire, disk, and backup keys have distinct owners and purposes |
+| `ARC-008` | exact parser, cache, queue, epoch, record, retry, fan-out, storage, and GC bounds |
+| `ARC-009` | replica, manifest, profile, capacity, and receipt failures stop without bypass or downgrade |
+| `IF-01` | only committed immutable storage request generations enter Composer export |
+| `IF-02` | replies are untrusted until KEMSphinx, storage, receipt, capability, and upper-protocol commit |
+| `IF-08` | the courier receives only the fixed opaque storage envelope after every mix layer |
+| `IF-09` | exact fixed courier/replica and replica/replica commands, receipts, repair, and bounds |
+| `IF-10` | one fresh single-use anonymous reply per transmitted request |
+| `TM-NET-01` | fixed shapes, independent schedules, cover requirement, bounded retries, no immediate MISS reaction |
+| `TM-NET-02` | rotating box IDs, directional streams, disjoint intermediates, fixed manifests, documented repeat-poll risk |
+| `TM-NET-03` | no immediate fallback, bounded fan-out, degraded-state gate, traffic simulation |
+| `TM-NET-04` | immutable request generations, courier dedup, idempotent final state, non-resurrection |
+| `TM-NET-05` | authenticated envelopes, box records, receipts, strict result binding, uniform remote failure |
+| `TM-NET-06` | consensus-authorized immutable profile, manifest, geometry, and application-independent behavior |
+| `TM-ROLE-03` | courier blindness, disjoint intermediate/final roles, two final receipts, separate state and keys |
+| `TM-ENDPOINT-01` | capability secrets stay in the Composer and commit before export or advancement |
+| `TM-ENDPOINT-03` | stale restore freezes streams, separate backups, no live-state copying |
+| `TM-APP-01` | one contact-specific writer stream, poisoned-slot handling, bounded payload before upper parsing |
+| `TM-OPS-01` | no capability, box, request, receipt, selection, or per-record telemetry |
+| `TM-CRYPTO-01` | complete lifecycle table, key purpose separation, bounded overlap and destruction |
+| `TM-CRYPTO-02` | fixed profile and manifest, withheld PQ claims, no fallback or self-selected suite |
+| `TM-AVAIL-01` | fixed fan-out, quotas, capacity limits, idempotency, GC, coarse overload, explicit admission gap |
+
+## 25. Open Dependencies
+
+The structural storage contract is fixed, but these dependencies remain open
+before an active profile or daemon:
+
+- exact BACAP, envelope, receipt, hash, signature, AEAD, and KDF revisions and
+ reviewed implementations;
+- resolution of upstream BACAP implementation maturity and audit gaps;
+- exact storage epoch duration, manifest overlap, retention, courier-cache,
+ polling, retry, cover, and shutdown parameters;
+- byte-exact forward, reply, FOG-WIRE, box, and messaging geometry;
+- a reviewed receipt construction and metadata analysis;
+- reviewed single-box capability attenuation for `fog-drop`;
+- safe anonymous admission and fair storage-flood control;
+- activation evidence for the structural FOG-COMPOSER vault, database,
+ external-anchor, and recovery profiles;
+- future bulk, atomic multi-box, group, and multi-device protocols.
+
+No implementation convenience may silently resolve these dependencies.
+
+## 26. Primary References
+
+- Katzenpost Pigeonhole protocol specification:
+ <https://katzenpost.network/docs/specs/pigeonhole/>
+- Katzenpost, Understanding Pigeonhole:
+ <https://katzenpost.network/docs/pigeonhole_explained/>
+- Katzenpost HPQC BACAP implementation:
+ <https://github.com/katzenpost/hpqc/tree/main/bacap>
+- Infeld et al., *Echomix: a Strong Anonymity System with Messaging*:
+ <https://arxiv.org/abs/2501.02933>
+- FOG threat model: `FOG-THREAT-MODEL.md`
+- FOG architecture: `FOG-ARCHITECTURE.md`
+- FOG public key infrastructure: `FOG-PKI.md`
+- FOG wire protocol: `FOG-WIRE.md`
+- FOG Sphinx profile framework: `FOG-SPHINX-PROFILES.md`
+- FOG messaging protocol: `FOG-MESSAGING.md`
+- FOG Composer protocol: `FOG-COMPOSER.md`
+
+These references supply a published construction, implementation target, and
+design lessons. They do not make the FOG integration secure by inheritance.
+FOG still requires exact profiles, geometry, vectors, implementation review,
+resource analysis, simulation, deployment evidence, and independent security
+review.
diff --git a/docs/FOG-SX.md b/docs/FOG-SX.md
new file mode 100644
index 0000000..336acae
--- /dev/null
+++ b/docs/FOG-SX.md
@@ -0,0 +1,1032 @@
+# FOG Simplex Transfer
+
+Status: Draft 0.1
+
+Date: 2026-08-08
+
+## 1. Purpose
+
+This document defines `FOG-SX`, the bounded, medium-independent simplex
+transfer contract used to move one committed opaque Composer export from a
+physically offline Composer toward an online blind relay.
+
+It fixes:
+
+- the transfer object and frame byte layouts;
+- padded transfer-size classes and their leakage;
+- profile selection without runtime negotiation;
+- forward-error-correction ownership and candidate gates;
+- acknowledgment-free sender and receiver state machines;
+- parser, memory, CPU, time, and storage ceilings;
+- common physical-backend requirements;
+- candidate QR, TOSLINK Lightpipe, and MIDI DIN profiles;
+- process isolation, failure behavior, and conformance evidence.
+
+This document records two non-active FEC candidates and three non-active
+physical-backend candidates. No candidate has an active numeric profile ID.
+No FOG-SX transfer is release-conformant until one complete joint profile has
+passed the activation gates in Section 22.
+
+The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, and MAY describe
+normative requirements in the sense of BCP 14 when they appear in uppercase.
+
+## 2. Scope
+
+FOG-SX owns the path:
+
+```text
+committed Composer RELAY_EXPORT bundle
+ -> sandboxed FOG-SX export encoder
+ -> physically transmit-only backend
+ -> one-way medium
+ -> physically receive-only backend
+ -> sandboxed FOG-SX transfer receiver
+ -> bounded reconstructed Composer bundle
+ -> blind-relay queue
+```
+
+FOG-SX version 1 carries exactly one complete Composer `RELAY_EXPORT` bundle
+per transfer. It does not carry a filename, directory, stream name, MIME type,
+URI, archive, compressed object, filesystem, document, script, executable, or
+device command.
+
+FOG-SX does not own:
+
+- Composer bundle semantics, record allowlists, or spool transitions;
+- KEMSphinx, messaging, storage, PKI, contact, update, or recovery
+ authentication;
+- blind-relay acceptance or delivery evidence;
+- online-to-offline Composer import;
+- a removable-media filesystem format;
+- generic optical, serial, audio, or camera device control;
+- anonymity, cover traffic, or traffic-analysis resistance on the physical
+ link.
+
+Online-to-offline input uses a separately controlled receive-only Composer
+path. It is not an FOG-SX acknowledgment channel and is not the reverse
+direction of the same peripheral.
+
+## 3. Security Boundary
+
+The raw backend stream, every frame header, every symbol, every FEC parameter,
+and every reconstructed transfer object are attacker-controlled input.
+
+The transfer receiver is outside the blind relay's trusted protocol state. It
+MUST NOT hold:
+
+- relay network credentials or Noise private keys;
+- Composer, user identity, messaging, storage, or PKI private keys;
+- message plaintext, contacts, capabilities, routes, or application state;
+- a shell, compiler, package manager, general browser, or general writable
+ filesystem;
+- a bidirectional interface to the offline Composer.
+
+The receiver outputs only one bounded byte string that still has to pass the
+complete `FOG-COMPOSER` bundle parser and every owning inner authentication
+rule. FEC recovery, CRC success, SHA-256 equality, transfer-ID equality,
+physical directionality, and operator observation confer no authenticity.
+
+Applicable requirements include `ARC-002`, `ARC-004`, `ARC-007`, `ARC-008`,
+`ARC-009`, `IF-01`, `IF-02`, `TM-ENDPOINT-01`, `TM-ENDPOINT-02`,
+`TM-OPS-01`, `TM-SUPPLY-01`, `TM-CRYPTO-01`, `TM-CRYPTO-02`, and
+`TM-AVAIL-01`.
+
+## 4. Version-1 Invariants
+
+Every active FOG-SX version-1 profile MUST preserve all of these invariants:
+
+1. Data flows in one physical direction during a transfer.
+2. The receiver sends no automatic acknowledgment, control, clock, retry,
+ negotiation, or completion signal to the sender.
+3. One exact joint profile is configured before transfer. There is no
+ autodetection, negotiation, opportunistic upgrade, or downgrade.
+4. Frames have one fixed size within a joint profile.
+5. One transfer contains one padded transfer object and one Composer bundle.
+6. Exact bundle length is hidden only within a declared size class.
+7. All integers use unsigned network byte order.
+8. Reserved bytes and unknown flags are zero. Any other value rejects the
+ frame or object.
+9. CRC32C and SHA-256 are error-detection and reconstruction checks only.
+10. The complete inner Composer bundle is validated before relay state
+ changes.
+11. Resource limits are checked before allocation or FEC work.
+12. The backend cannot introduce filenames, metadata records, control
+ messages, or an automatic return path.
+13. Unknown profile, frame, size-class, and FEC identifiers fail closed.
+14. Profile behavior is immutable for its numeric identifier.
+
+## 5. Terms
+
+- `ComposerBundle`: the byte-exact object defined by `FOG-COMPOSER`.
+- `TransferObject`: the 128-byte FOG-SX object header, one ComposerBundle,
+ and zero padding to an exact size-class capacity.
+- `source symbol`: one fixed-length slice used by the selected FEC.
+- `repair symbol`: one FEC-generated symbol that is not an original source
+ symbol.
+- `source block`: one independently recoverable group of source symbols.
+- `frame`: one 96-byte FOG-SX header, one symbol payload, and one trailing
+ CRC32C.
+- `joint profile`: the immutable tuple of format, backend, FEC, size,
+ scheduling, and resource parameters accepted by both endpoints.
+- `receive window`: one explicit local operator action that permits the
+ receiver to admit a new transfer.
+- `completion indication`: local human-visible receiver output. It is not a
+ protocol message.
+
+## 6. Profile Registry
+
+### 6.1 Joint profile
+
+An `sx_profile_id` identifies one complete immutable registry entry containing
+at least:
+
+- FOG-SX format version;
+- permitted transfer direction and Composer bundle kind;
+- backend profile ID and hardware assurance level;
+- FEC profile ID, exact algorithm revision, and implementation constraints;
+- allowed size-class IDs;
+- symbol payload length;
+- object partitioning into source blocks and symbols;
+- encoding-symbol-ID range and mapping;
+- systematic, repair, interleaving, and repetition schedule;
+- physical framing, modulation, bitrate, clock recovery, and timeout;
+- CRC32C representation;
+- sender cycle and duration ceilings;
+- receiver frame, memory, storage, CPU, conflict, and decode-attempt budgets;
+- release, dependency, and test-vector identity.
+
+The separately encoded backend, FEC, and size-class IDs let the receiver
+reject inconsistent headers early. They do not permit the sender to assemble
+a new tuple. Every field MUST equal the configured joint-profile entry.
+
+### 6.2 Distribution and activation
+
+The registry ships as immutable release data. It is not learned from the raw
+stream. Numeric ID zero is invalid. Candidate names in this document are
+symbolic and MUST NOT be placed on the wire as numeric IDs.
+
+Changing an algorithm, parameter, schedule, dependency, hardware assumption,
+or parser limit requires a new joint profile ID. An implementation MUST NOT
+reinterpret an old ID after an update.
+
+The operator selects one backend and one joint profile before opening a
+receive window. A decoder MUST NOT scan multiple frame formats, CRC variants,
+FEC schemes, or physical modulations to discover what the sender meant.
+
+## 7. Padded Size Classes
+
+### 7.1 Class definition
+
+A size class fixes `bundle_capacity`, the maximum number of ComposerBundle
+bytes carried in its TransferObject. The exact FEC source length is:
+
+```text
+transfer_object_length = 128 + bundle_capacity
+```
+
+The TransferObject is:
+
+```text
+128-byte TransferObjectHeader
+composer_bundle_length bytes of ComposerBundle
+bundle_capacity - composer_bundle_length zero bytes
+```
+
+The sender selects the smallest class permitted by the joint profile whose
+capacity is at least the exact committed bundle length. The sender MUST NOT
+repack, reorder, compress, split, or semantically modify the committed bundle
+to obtain another class.
+
+### 7.2 Version-1 structural class table
+
+The structural registry reserves these capacities. A joint profile activates
+only an explicit subset.
+
+| Symbolic class | `bundle_capacity` | Intended use |
+| --- | ---: | --- |
+| `SX-C16K-1` | 16 KiB | small fixtures and constrained visual trials |
+| `SX-C64K-1` | 64 KiB | small relay batches |
+| `SX-C256K-1` | 256 KiB | ordinary relay batches |
+| `SX-C1M-1` | 1 MiB | large relay batches |
+| `SX-C4M-1` | 4 MiB | optical-only candidate |
+| `SX-C16M-1` | 16 MiB | optical-only candidate |
+| `SX-C64M-1` | 64 MiB | Composer relay parser ceiling |
+
+`KiB` and `MiB` mean powers of 1024. No version-1 FOG-SX class exceeds 64 MiB
+of bundle capacity. Update, recovery, contact, and import bundles are outside
+the version-1 FOG-SX direction even when their Composer limits would fit.
+
+### 7.3 Leakage
+
+Padding hides only the exact bundle length inside the selected class. A
+physical observer and the receiver can observe at least the backend, timing,
+class, frame count, losses, repetition duration, and operator behavior.
+
+The systematic source symbols of the same committed Composer bundle remain
+correlatable across retransfers even when the transfer ID changes. FOG-SX
+does not claim rerandomization or unlinkability. A future authenticated and
+encrypted local Composer-relay envelope would be a separate Composer profile,
+not an implicit property of FOG-SX.
+
+## 8. TransferObject Header
+
+### 8.1 Exact 128-byte layout
+
+```text
+offset length field
+0 8 magic
+8 2 sx_format_version
+10 1 object_kind
+11 1 flags
+12 4 sx_profile_id
+16 4 backend_profile_id
+20 4 fec_profile_id
+24 4 size_class_id
+28 32 transfer_id
+60 8 composer_bundle_length
+68 8 transfer_object_length
+76 32 composer_bundle_digest
+108 16 reserved
+124 4 header_checksum
+```
+
+`magic` is the eight ASCII octets `FOGSXO1` followed by line feed, with hex
+value `46 4f 47 53 58 4f 31 0a`.
+
+`sx_format_version` is 1. `object_kind` is 1 for `RELAY_EXPORT`.
+`flags` is zero. `reserved` is sixteen zero octets.
+
+`transfer_id` is exactly 32 bytes sampled from the operating system CSPRNG for
+one new transfer attempt. It is not a user identity, authenticity value,
+nonce for encryption, replay token, or receipt.
+
+`composer_bundle_length` is the exact byte length of the committed bundle.
+It MUST be at least the 128-byte Composer outer header and no greater than the
+selected `bundle_capacity` or the Composer `RELAY_EXPORT` limit.
+
+`transfer_object_length` MUST equal `128 + bundle_capacity` for the selected
+class. It is redundant by design and MUST match the registry before the
+receiver allocates object storage.
+
+`composer_bundle_digest` is SHA-256 over the exact ComposerBundle bytes only,
+not over TransferObject padding. It detects reconstruction and storage errors
+and supports local duplicate handling. Because it is unkeyed and sent with
+the object, an attacker can replace it. It provides no authenticity.
+
+### 8.2 Header checksum
+
+`header_checksum` is CRC32C using the algorithm and wire representation of
+RFC 3309. For calculation, the four header-checksum octets are zero. The CRC
+covers all 128 header octets and does not cover the bundle or padding.
+
+The decoded header is not trusted merely because its CRC is correct. The
+receiver validates it against frame fields and the configured registry before
+using lengths or counts.
+
+### 8.3 Canonical padding
+
+Every byte after the exact ComposerBundle and before the end of the selected
+TransferObject MUST be zero. Non-zero padding rejects the complete object.
+Trailing data beyond `transfer_object_length` is not part of the object and
+cannot be delivered to the relay.
+
+## 9. SXFrame
+
+### 9.1 Exact 96-byte header
+
+```text
+offset length field
+0 8 magic
+8 2 sx_format_version
+10 1 frame_kind
+11 1 flags
+12 4 sx_profile_id
+16 4 backend_profile_id
+20 4 fec_profile_id
+24 4 size_class_id
+28 32 transfer_id
+60 4 source_block_number
+64 4 source_block_count
+68 4 source_symbol_count
+72 4 encoding_symbol_id
+76 4 symbol_length
+80 12 reserved
+92 4 header_checksum
+```
+
+The fixed frame is:
+
+```text
+96-byte SXFrameHeader
+symbol_length bytes of symbol_payload
+4-byte frame_checksum
+```
+
+`magic` is the eight ASCII octets `FOGSXF1` followed by line feed, with hex
+value `46 4f 47 53 58 46 31 0a`.
+
+`sx_format_version` is 1. `frame_kind` is 1 for `SYMBOL`. No `END`, `ACK`,
+`NAK`, negotiation, capability, metadata, filename, or control frame exists
+in version 1. Backend idle and acquisition patterns remain outside SXFrame
+and carry no transfer data.
+
+`flags` and `reserved` are zero. `symbol_length` equals the joint profile's
+fixed symbol payload length. Every frame in the profile therefore has exactly
+`100 + symbol_length` bytes.
+
+### 9.2 Block and symbol fields
+
+`source_block_count` and `source_symbol_count` are redundant values derived
+from the size class and FEC profile. They MUST match the registry calculation.
+
+`source_block_number` is less than `source_block_count`.
+`encoding_symbol_id` is interpreted only by the configured FEC profile and
+MUST be inside that profile's declared range for the block.
+
+The tuple:
+
+```text
+(sx_profile_id, transfer_id, source_block_number, encoding_symbol_id)
+```
+
+identifies one candidate symbol. It is not authenticated. Two byte-identical
+copies are duplicates. Two different payloads for the same tuple are a
+conflict and trigger the bounded conflict policy in Section 15.
+
+### 9.3 Checksums
+
+`header_checksum` is CRC32C over the complete 96-byte header with that field
+zero. It permits early rejection before symbol allocation.
+
+`frame_checksum` is CRC32C over the transmitted 96-byte header, including its
+filled header checksum, followed by the exact symbol payload. The trailing
+frame-checksum field is excluded from its own calculation.
+
+Both CRC values use RFC 3309 CRC32C. A mismatch silently discards the frame.
+A matching CRC does not authenticate the sender or symbol.
+
+## 10. FEC Contract
+
+### 10.1 Ownership
+
+The FEC profile, not the raw stream, fixes:
+
+- exact standard and revision;
+- source-object partition algorithm;
+- symbol alignment and length;
+- minimum and maximum source symbols per block;
+- source-block count calculation;
+- source and repair encoding-symbol-ID mapping;
+- maximum accepted ESI;
+- repair-symbol generation;
+- decoder input-selection and conflict rules;
+- decode-attempt thresholds and maximum attempts;
+- per-block memory, operation, and wall-time budgets;
+- exact implementation and license evidence accepted for release;
+- deterministic positive and negative vectors.
+
+FEC parameters MUST NOT be inferred from attacker-selected counts. The frame
+counts are checked copies of values derived from the configured profile and
+size class.
+
+### 10.2 Source partition
+
+The complete padded TransferObject is the FEC source object. The profile
+partitions it into ordered source blocks and fixed-length source symbols.
+Only the last source symbol of the last block may require FEC-internal zero
+fill, and the profile must make this fill byte-exact and distinguish it from
+TransferObject padding.
+
+Each source block decodes independently. Receiver code MUST NOT allocate the
+entire candidate FEC matrix when one block is being decoded unless the active
+profile's reviewed memory bound explicitly permits it.
+
+### 10.3 Corruption and injection
+
+FEC corrects erasures and some physical errors after failed frames are
+discarded. It does not provide integrity against a malicious sender. One
+forged but CRC-consistent encoding symbol may poison a decode.
+
+After all blocks decode, the receiver therefore validates, in order:
+
+1. exact TransferObject length;
+2. exact 128-byte header and header CRC32C;
+3. all profile, transfer, length, kind, reserved, and padding fields;
+4. SHA-256 over the exact ComposerBundle;
+5. exact Composer outer structure and direction;
+6. owning inner authentication in the relay or Composer processing path.
+
+A failure at any step discards the reconstructed candidate and makes no relay
+state change.
+
+## 11. Non-Active FEC Candidates
+
+### 11.1 RaptorQ candidate
+
+`FOG-SX-CANDIDATE-RAPTORQ-RFC6330-1` evaluates the fully specified RaptorQ
+scheme in RFC 6330.
+
+Potential advantages:
+
+- systematic source symbols;
+- repair symbols generated as needed without a fixed transmitted total;
+- good fit for acknowledgment-free repeated emission;
+- substantially larger source blocks than GF(256) Reed-Solomon.
+
+Required review items:
+
+- exact RFC parameter derivation and ESI mapping;
+- decoder CPU and memory behavior on malformed or adversarial symbols;
+- constant parser ceilings far below RFC maximums where appropriate;
+- maintained implementation quality, unsafe-language containment, fuzzing,
+ and cross-implementation vectors;
+- dependency license and the IETF RaptorQ IPR disclosures, including the
+ conditions and defensive-assertion language of disclosure 2554;
+- full-object corruption and injection handling before relay delivery.
+
+No implementation may claim that the RFC's large theoretical object limit is
+a FOG-SX permission to allocate or process that amount.
+
+### 11.2 Reed-Solomon candidate
+
+`FOG-SX-CANDIDATE-RS-GF256-RFC5510-1` evaluates systematic Reed-Solomon over
+GF(2^8) using the fully specified construction in RFC 5510.
+
+Potential advantages:
+
+- mature, deterministic block-code behavior;
+- recovery of `k` source symbols from any `k` valid encoding symbols for the
+ specified MDS construction;
+- simpler finite redundancy and decode scheduling for small blocks.
+
+Constraints:
+
+- GF(2^8) provides at most 255 encoding symbols per source block;
+- the profile must fix `k`, `n`, redundancy, block partitioning, and the
+ behavior after all `n` symbols have been emitted;
+- additional repetition cannot create new repair symbols beyond the fixed
+ codeword and therefore handles burst losses less flexibly than a fountain
+ schedule;
+- poisoned CRC-consistent symbols can still corrupt a decoded block.
+
+### 11.3 Selection rule
+
+Neither candidate is selected by this draft. Selection requires measured
+results for all activated size and backend classes, complete license review,
+dependency maintenance evidence, bounded hostile-input tests, independent
+vectors, and reproducible resource measurements.
+
+An implementation MAY build isolated experimental adapters for both
+candidates. It MUST NOT assign a production numeric ID or silently choose one
+at runtime.
+
+## 12. Sender State Machine
+
+The sender uses these states:
+
+```text
+IDLE
+ -> PREPARED
+ -> EMITTING
+ -> STOPPED
+
+PREPARED or EMITTING
+ -> FAILED
+```
+
+### 12.1 Prepare
+
+To enter `PREPARED`, the export encoder:
+
+1. receives read-only access to one immutable committed Composer spool item;
+2. verifies exact bundle length and the selected size class;
+3. samples a fresh 32-byte transfer ID from the OS CSPRNG;
+4. creates the canonical TransferObject header;
+5. streams the bundle and zero padding into the FEC encoder;
+6. derives every block and schedule parameter from the configured registry;
+7. confirms sender memory, time, frame, and output-device budgets;
+8. closes every input not required for emission.
+
+It does not parse message contents or query Composer state. Failure creates no
+partial success indication and does not mutate the committed Composer bundle.
+
+### 12.2 Emit
+
+The joint profile defines one deterministic cycle containing systematic and
+repair symbols interleaved across source blocks. The schedule SHOULD disperse
+adjacent source data and block repair across time so that one physical burst
+does not erase a contiguous object region.
+
+The exact schedule, repair quota, block permutation, and ESI sequence are
+profile inputs, not operator options. The sender repeats complete cycles until
+one of:
+
+- the human explicitly stops after observing receiver completion;
+- the configured maximum cycle count is reached;
+- the configured monotonic-duration ceiling is reached;
+- the backend or resource monitor fails closed.
+
+The sender never waits for receiver data and never changes its schedule based
+on light, sound, serial input, network input, USB control input, or timing
+purportedly supplied by the receiver.
+
+### 12.3 Stop and retry
+
+Stopping emission does not mean the relay accepted, queued, or delivered the
+bundle. It records only a local transmitter event.
+
+A new manual transfer attempt uses a fresh transfer ID. It MAY reuse the exact
+committed ComposerBundle while its spool-retention policy permits. It MUST NOT
+rewind message, ratchet, storage, packet, or Composer state merely because the
+physical transfer was stopped or failed.
+
+## 13. Receiver State Machine
+
+The receiver uses:
+
+```text
+CLOSED
+ -> ARMED
+ -> COLLECTING
+ -> RECONSTRUCTING
+ -> COMPLETE
+
+ARMED, COLLECTING, or RECONSTRUCTING
+ -> FAILED
+
+COMPLETE or FAILED
+ -> CLOSED
+```
+
+### 13.1 Arm
+
+`CLOSED` admits no new transfer. An explicit local operator action chooses
+the backend, joint profile, and allowed size classes and opens one bounded
+receive window.
+
+The high-assurance receiver admits at most one active transfer. It creates no
+state from idle patterns, CRC-failed data, unknown IDs, or a frame that does
+not match the configured profile.
+
+### 13.2 Collect
+
+The first valid frame may establish the candidate transfer ID and size class
+only after all fixed header, CRC, profile, and derived-count checks pass.
+Later frames with another transfer ID are silently dropped while the slot is
+occupied.
+
+For one symbol tuple, the receiver:
+
+- stores the first CRC-valid payload within budget;
+- ignores an exact byte-identical duplicate;
+- counts a different CRC-valid payload as a conflict;
+- never lets a conflicting later payload silently replace an earlier one;
+- aborts the transfer when the profile conflict ceiling is exceeded.
+
+Symbols are stored in bounded per-block structures. Raw physical frames and
+failed frames are not retained after the minimal counters needed for the
+local status display.
+
+### 13.3 Reconstruct
+
+The decoder attempts one block only at profile-defined unique-symbol
+thresholds and intervals. Receipt of duplicates, conflicts, bad CRCs, or
+arbitrary ESIs MUST NOT trigger unbounded repeated matrix work.
+
+Decoded blocks are staged in their exact object offsets. The receiver cannot
+publish a partial object. After every block is present, it performs the full
+validation sequence in Section 10.3 and streams the exact ComposerBundle into
+one exclusively created bounded relay-ingress object.
+
+### 13.4 Complete
+
+`COMPLETE` means only that one byte-exact candidate passed FOG-SX structural
+validation and was durably handed to the bounded relay-ingress queue. It does
+not mean inner authentication, network submission, storage commit, or final
+delivery succeeded.
+
+The receiver MAY show a local light, fixed icon, or coarse text indication to
+the human. It MUST NOT send a frame, network callback, sound, optical flash,
+USB control transfer, or other automatic completion signal to the sender.
+
+## 14. Validation Order Before Allocation
+
+For each backend-delivered candidate frame, the receiver performs:
+
+1. enforce the exact backend unit length;
+2. locate the one profile-defined frame boundary without format scanning;
+3. validate magic and version;
+4. require `frame_kind = SYMBOL`, zero flags, and zero reserved bytes;
+5. compare all profile IDs with the configured joint profile;
+6. require the exact fixed symbol length;
+7. validate the header CRC32C;
+8. validate the complete frame CRC32C;
+9. derive and compare size, block, source-symbol, and ESI bounds;
+10. enforce active-transfer, duplicate, conflict, storage, and work budgets;
+11. only then copy the symbol into bounded FEC storage.
+
+All additions and multiplications involving untrusted fields use checked
+integer arithmetic. A decoder MUST NOT cast an untrusted 32-bit count to a
+smaller type, allocate from it, or multiply it before checking the profile-
+derived expected value.
+
+## 15. Version-1 Absolute Ceilings
+
+These are implementation ceilings. Active profiles MUST be equal or stricter.
+
+| Resource | Absolute ceiling |
+| --- | ---: |
+| Frame header | exactly 96 bytes |
+| Symbol payload | 4096 bytes |
+| Complete frame | 4196 bytes |
+| TransferObject header | exactly 128 bytes |
+| Composer bundle capacity | 64 MiB |
+| TransferObject length | 64 MiB + 128 bytes |
+| Active transfer IDs, high assurance | 1 |
+| Active transfer IDs, lower assurance | 2 |
+| Source blocks per transfer | 65536 |
+| Source symbols per block | 4096 |
+| Accepted unique symbols per block | 8192 |
+| Conflicting tuples per block | 16 |
+| FEC decode attempts per block | 32 |
+| Simultaneous block decoders | 2 |
+| Staged decoded object bytes | one selected TransferObject |
+| Retained failed raw frames | 0 |
+| Receive window | 24 monotonic hours |
+| Sender cycles | 65535 |
+| Parser nesting | forbidden |
+| Decompression | forbidden |
+
+The active profile defines lower backend-appropriate duration, cycle, block,
+symbol, memory, disk, and CPU budgets. The receiver stops accepting symbols
+while a block decode consumes its quota. A timeout, disk-full condition,
+memory-pressure event, excessive conflict rate, dependency panic, or budget
+exhaustion aborts the candidate and returns to a safe closed state.
+
+Counters used only for resource enforcement saturate rather than wrap. They
+are reset when the receive window closes and are not exported as telemetry.
+
+## 16. Duplicate, Replay, and Injection Behavior
+
+FOG-SX has no authenticated replay protection. A malicious source can copy or
+recreate all of its public fields and checksums.
+
+The receiver MAY maintain a bounded local cache of recently completed tuples:
+
+```text
+(sx_profile_id, transfer_id, composer_bundle_digest,
+ composer_bundle_length, size_class_id)
+```
+
+An exact completed duplicate can be discarded before a second relay-ingress
+write. The cache is a local availability control, not proof that another
+transfer with the same ID or digest is authentic.
+
+Composer and the owning inner protocols retain final deduplication and replay
+authority. A new transfer ID does not authorize a duplicate message, receipt,
+storage write, or state transition.
+
+## 17. Common Physical-Backend Contract
+
+Every backend profile fixes:
+
+- one direction and one physical transmitter/receiver role;
+- exact connector, module class, and electrical or optical assumptions;
+- raw carrier framing and acquisition pattern;
+- modulation, line coding, symbol rate, bitrate, and clock tolerance;
+- mapping from one complete SXFrame to carrier units;
+- acquisition, frame, idle, loss, and end-of-window timeouts;
+- maximum supported size classes and expected transfer duration;
+- device-open flags, driver allowlist, and prohibited device capabilities;
+- physical teardown, continuity, and direction tests;
+- emitted-light, sound, electromagnetic, and human-visible safety constraints;
+- deterministic vectors captured above and below the backend boundary.
+
+Backend code transports exact SXFrame bytes. It MUST NOT reinterpret a frame
+as text, Base64, a file, MIDI music, audio content, a URL, or a document unless
+the specific profile defines one fixed byte mapping solely as carrier coding.
+
+The high-assurance profile requires separate unidirectional components whose
+physical construction enforces direction. Software configuration, a disabled
+receive API, driver policy, or a supposedly unused bidirectional transceiver
+is insufficient.
+
+The offline side exposes only a transmitter data input. The online side
+exposes only a receiver data output. No common USB controller, shared debug
+UART, management bus, network interface, storage controller, radio, or
+bidirectional data cable may bridge the trust domains.
+
+## 18. QR Candidate
+
+`FOG-SX-CANDIDATE-QR-MODEL2-1` uses fixed-version QR Code Model 2 symbols as a
+visual carrier from an offline display to an online camera.
+
+Before activation it must fix:
+
+- the ISO/IEC 18004 edition;
+- QR version, byte mode, mask selection rule, and error-correction level;
+- one exact binary mapping with one complete SXFrame per QR symbol and no QR
+ structured append or backend-level SXFrame fragmentation;
+- quiet zone, module size, contrast, display refresh, dwell, and blanking;
+- camera resolution, frame rate, exposure, focus, decoder, and timeout;
+- maximum FOG-SX size classes and operator ergonomics;
+- rejection of URLs, text actions, structured append outside the exact
+ profile, and general barcode dispatch.
+
+QR Code has its own Reed-Solomon error correction. That layer improves visual
+recovery but does not authenticate FOG-SX or replace the frame CRC, object
+digest, FEC profile, or inner Composer authentication.
+
+The camera is an attack surface. The online receiver uses a dedicated camera
+or capture path with no microphone, speaker, storage automount, network,
+vendor cloud service, or automatic barcode action. An online display used for
+separate Composer import is not an acknowledgment and must not be driven by
+FOG-SX receive state.
+
+## 19. FOG Lightpipe Candidate
+
+`FOG-SX-CANDIDATE-LIGHTPIPE-NRZ-1` is the preferred high-throughput candidate.
+It uses a discrete optical transmitting module on the offline side, one fiber,
+and a discrete optical receiving module on the online side.
+
+The high-assurance construction requires:
+
+- a transmitter-only module, such as the TOSLINK `TOTX` class;
+- a receiver-only module, such as the TOSLINK `TORX` class;
+- no `TODX` transceiver, duplex module, second fiber, or receiver on the
+ offline board;
+- no transmitter, display-controlled return light, or software-controlled
+ emitter on the online board;
+- galvanically separated power and no data-bearing ground or debug path
+ between boards;
+- a simple allowlisted hardware interface whose offline driver can only emit
+ and whose online driver can only receive;
+- schematics, bill of materials, board photographs, continuity tests, optical
+ direction tests, and teardown evidence for the exact hardware revision.
+
+TOSLINK defines optical transmitter and receiver device classes, not the
+complete FOG-SX modulation. Before activation the candidate must fix the exact
+NRZ or self-clocking line code, bitrate, transition density, preamble, clock
+recovery, frame delimiter, escaping, idle pattern, light polarity, optical
+module, fiber, distance, jitter, and error tests.
+
+Consumer S/PDIF or USB audio adapters are lower assurance. They may contain
+bidirectional USB control, opaque firmware, audio clocks, mixers, microphones,
+or unexpected device functions. They MUST NOT satisfy the high-assurance
+Lightpipe profile merely because their payload leaves through an optical jack.
+
+A second online-to-offline optical system, if ever deployed for Composer
+import, is a separately powered, separately controlled path with its own
+receive-only offline hardware. It is not simultaneously active, is not
+connected to FOG-SX state, and does not turn the export construction into a
+duplex protocol.
+
+## 20. MIDI DIN Candidate
+
+`FOG-SX-CANDIDATE-MIDI-DIN-1` uses one MIDI DIN OUT circuit to one optically
+isolated MIDI DIN IN circuit as a lower-throughput experimental carrier.
+
+The MIDI 1.0 electrical specification defines a 31.25 kbaud asynchronous
+8-N-1 interface, a 5 mA current loop, and receiver opto-isolation. The active
+candidate must use that electrical direction, not a bidirectional USB MIDI
+device.
+
+Before activation it must fix:
+
+- exact byte transparency and framing above the MIDI serial byte;
+- handling or prohibition of status-byte semantics and running status;
+- escaping, preamble, frame delimiter, resynchronization, and idle behavior;
+- maximum frame payload and size class consistent with transfer duration;
+- compliant OUT, IN, cable, shield, grounding, and opto-isolator circuits;
+- absence of MIDI THRU or any offline input path;
+- hostile jitter, disconnect, stuck-bit, burst-loss, and opto-isolator tests.
+
+The carrier must not expose FOG-SX bytes to a general music application,
+synthesizer plugin, device-discovery service, or cloud-connected MIDI stack.
+
+## 21. Other Backends
+
+Visible LED, screen-to-photodiode, audible modem, opto-isolated TX-only serial,
+and punched paper tape remain architectural possibilities. None is specified
+by this document and none may reuse a QR, Lightpipe, or MIDI backend ID.
+
+Each future backend needs its own threat analysis, exact physical and byte
+mapping, hardware-direction proof, resource profile, conformance vectors, and
+release gate. A generic runtime driver or modulation plugin system is not a
+substitute for separately reviewed profiles.
+
+## 22. Candidate Activation Gates
+
+A joint FOG-SX profile receives a numeric ID only after all of these are
+complete:
+
+1. byte-exact frame, object, size, FEC, schedule, and backend parameters;
+2. two independent encoders and decoders or one implementation plus an
+ independent vector generator;
+3. known-answer vectors for every size class and boundary value;
+4. dependency, license, IPR, maintenance, and supply-chain review;
+5. parser fuzzing with malformed headers, lengths, IDs, CRCs, padding, and
+ trailing data;
+6. hostile FEC corpus covering duplicates, conflicts, poisoned symbols,
+ excessive ESIs, singular decode inputs, and resource exhaustion;
+7. reproducible CPU, memory, disk, frame, time, and energy measurements;
+8. crash, interruption, power-loss, disk-full, and restart testing;
+9. physical directionality inspection and tests for the exact hardware;
+10. confirmation that no automatic sender-visible completion path exists;
+11. complete Composer and relay integration with inner authentication before
+ state change;
+12. independent security review of parser, FEC, hardware, and claims.
+
+A local loopback, virtual QR camera, paired serial ports, audio adapter, or
+single board can provide functional evidence only. It cannot establish a
+physical data-diode or production endpoint-security claim.
+
+## 23. Implementation Shape
+
+The protocol implementation should preserve these logical modules:
+
+```text
+protocol/sx/
+ frame/ fixed header parsing, serialization, and CRC
+ object/ TransferObject construction, padding, and validation
+ profile/ immutable registry and derived parameter checks
+ fec/ narrow profile-specific encoder and decoder interfaces
+ schedule/ deterministic sender schedule
+ receiver/ bounded collection and reconstruction state machine
+ backend/
+ qr/ exact visual carrier edge
+ lightpipe/ exact optical carrier edge
+ midi/ exact current-loop carrier edge
+```
+
+The process boundary is:
+
+```text
+offline: fog-compose -> sealed spool -> fog-sx-send -> TX-only device
+online: RX-only device -> fog-sx-receive -> bounded relay ingress
+```
+
+`frame`, `object`, and profile validation are pure protocol code and do not
+open devices or files. FEC implementations receive already bounded slices and
+profile constants. Backend modules do not parse Composer bundles or implement
+FEC. The transfer receiver is a separate executable from `fog-client-relay`.
+
+There is no generic plugin loader, dynamic library selected by wire input,
+universal device daemon, or in-process backend autodetection. Candidate FEC
+libraries written in an unsafe language run behind the narrowest practical
+sandbox and process boundary with fixed memory and CPU limits.
+
+## 24. State, Retention, and Logging
+
+The offline sender may read only the selected immutable spool item and its
+public transfer profile. It stores no new long-term secret. Transfer IDs are
+public ephemeral metadata and follow the spool attempt's bounded lifetime.
+
+The online receiver retains:
+
+- one bounded active symbol set during a receive window;
+- one staged decoded TransferObject until complete validation;
+- one exact ComposerBundle until durable relay-ingress handoff;
+- a bounded recent-completion cache if enabled;
+- coarse saturating error counters for the current local session.
+
+It deletes failed symbols, failed objects, padding, and raw frames after the
+owning failure or completion path. Deletion is best effort on flash and other
+journaled storage and is not claimed as forensic erasure.
+
+Logs and support output MUST NOT contain raw frames, symbols, transfer IDs,
+bundle digests, Composer bytes, frame timing traces, device serial numbers,
+camera images, audio captures, filesystem paths, or host identity. Local
+status may show coarse progress, current class, and a generic failure category
+without exporting telemetry.
+
+## 25. Conformance Tests
+
+Before the local PoC, deterministic tests must cover:
+
+- exact 128-byte object and 96-byte frame headers;
+- both magic values, version, kind, zero flags, and reserved bytes;
+- big-endian integers and checked arithmetic;
+- every boundary around each size class and the 64 MiB ceiling;
+- exact zero padding and rejection of non-zero or trailing bytes;
+- SHA-256 and both CRC32C calculation domains and wire values;
+- wrong profile tuple, symbol length, counts, block number, and ESI;
+- exact duplicate and conflicting symbols;
+- all FEC success, insufficient-symbol, poisoned-symbol, and abort paths;
+- deterministic schedule and interleaving across cycles;
+- receiver window, transfer-slot, decode-attempt, time, memory, disk, and CPU
+ limits;
+- no partial output after any frame, block, object, or Composer failure;
+- exact one-bundle relay-ingress handoff and duplicate suppression;
+- sender stop and retry without state rewind;
+- absence of ACK, reverse device access, network callback, and adaptive
+ sender behavior;
+- each physical backend's acquisition, loss, jitter, disconnect, and
+ directionality fixtures;
+- mutation, coverage-guided fuzz, property, race, crash, and fault-injection
+ testing at every parser and process boundary.
+
+Cross-implementation vectors include exact TransferObject bytes, every source
+and repair symbol, frame bytes, CRCs, schedule order, reconstructed bytes, and
+expected rejection reason class. Rejection classes are test outputs, not
+remote protocol responses.
+
+## 26. Failure Behavior
+
+Malformed, unknown, inconsistent, oversized, stale, conflicting, timed-out,
+or resource-exhausting input fails closed. The receiver sends nothing toward
+the transmitter and publishes no partial Composer bundle.
+
+The local UI distinguishes only coarse states such as waiting, collecting,
+checking, complete, timed out, incompatible profile, and failed. Detailed
+parser positions, CRC values, FEC matrices, raw input, transfer IDs, and
+digests are unavailable to the physical sender and excluded from ordinary
+logs.
+
+If completion is uncertain, the human may stop and later restart a fresh
+transfer attempt. Neither endpoint treats uncertainty as permission to bypass
+Composer deduplication, inner authentication, or protocol state rules.
+
+## 27. Threat and Architecture Traceability
+
+| Requirement | Primary controls |
+| --- | --- |
+| `ARC-002` | networkless Composer, TX-only export, no automatic reverse path |
+| `ARC-004` | transfer receiver has no relay, user, messaging, or storage keys |
+| `ARC-007` | no FOG-SX secret; explicit ephemeral transfer-ID ownership |
+| `ARC-008` | exact headers, fixed frames, derived counts, absolute ceilings |
+| `ARC-009` | unknown profile, corruption, ambiguity, and exhaustion fail closed |
+| `IF-01` | one committed opaque export, sandboxed encoder and receiver |
+| `IF-02` | import remains a separate controlled direction, never an ACK path |
+| `TM-ENDPOINT-01` | dedicated offline process and directional hardware assumptions |
+| `TM-ENDPOINT-02` | bounded binary format, parser sandbox, no archive or filesystem |
+| `TM-OPS-01` | no raw transfer logging, device identity, telemetry, or support dump |
+| `TM-SUPPLY-01` | exact dependencies, hardware revision, license and release gates |
+| `TM-CRYPTO-01` | CSPRNG transfer IDs, SHA-256 limited to error detection |
+| `TM-CRYPTO-02` | immutable release registry, no negotiation or downgrade |
+| `TM-AVAIL-01` | receive windows, one slot, conflict and FEC work budgets |
+
+## 28. Claims Deliberately Withheld
+
+FOG-SX does not yet establish:
+
+- an active FEC algorithm, implementation, or numeric profile;
+- an active physical backend, bitrate, symbol size, or hardware design;
+- physical one-way assurance from software configuration alone;
+- authenticity, confidentiality, replay protection, or non-repudiation at the
+ FOG-SX layer;
+- unlinkability of retransferred Composer bundles;
+- concealment of transfer occurrence, timing, size class, frame count, or
+ physical location;
+- resistance to a compromised offline Composer, online receiver, firmware,
+ camera, USB controller, optical module, or supply chain;
+- elimination of optical, acoustic, electromagnetic, thermal, power, or
+ human-mediated covert channels;
+- production security from a loopback, animated QR demo, consumer TOSLINK
+ adapter, USB MIDI adapter, or local PoC;
+- successful network delivery merely because local reconstruction completed.
+
+## 29. Open Dependencies
+
+The structural FOG-SX contract is fixed, but these remain open:
+
+- selection between the RaptorQ and Reed-Solomon candidates or a separately
+ reviewed replacement;
+- exact FEC parameters, implementation, dependency version, and license
+ decision;
+- byte-exact joint profile IDs and size-class subsets;
+- exact QR geometry, decoder, frame mapping, and transfer-duration limits;
+- exact Lightpipe modules, board, line code, bitrate, clock recovery, and
+ hardware-direction evidence;
+- exact MIDI byte mapping, circuit, frame size, and practical size classes;
+- concrete per-profile CPU, memory, disk, cycle, time, and energy limits;
+- Composer pairing-envelope decision if rerandomized local transport is later
+ required;
+- conformance corpus, fault fixtures, benchmark results, and independent
+ review.
+
+No implementation convenience may silently resolve these dependencies.
+
+## 30. Primary References
+
+- FOG threat model: `FOG-THREAT-MODEL.md`
+- FOG architecture: `FOG-ARCHITECTURE.md`
+- FOG Composer: `FOG-COMPOSER.md`
+- RFC 6330, RaptorQ Forward Error Correction Scheme for Object Delivery:
+ <https://www.rfc-editor.org/rfc/rfc6330.html>
+- IETF IPR disclosure 2554 related to RFC 6330:
+ <https://datatracker.ietf.org/ipr/2554/>
+- RFC 5510, Reed-Solomon Forward Error Correction Schemes:
+ <https://www.rfc-editor.org/rfc/rfc5510.html>
+- RFC 3309, SCTP Checksum Change, including CRC32C definition:
+ <https://www.rfc-editor.org/rfc/rfc3309.html>
+- FIPS PUB 180-4, Secure Hash Standard:
+ <https://csrc.nist.gov/pubs/fips/180-4/upd1/final>
+- ISO/IEC 18004:2024, QR code symbology specification:
+ <https://www.iso.org/standard/83389.html>
+- DENSO WAVE QR Code error-correction overview:
+ <https://www.qrcode.com/en/about/error_correction.html>
+- MIDI 1.0 Electrical Specification Update:
+ <https://midi.org/5-pin-din-electrical-specs>
+- Toshiba TOSLINK transmitter, receiver, transceiver, and directivity naming:
+ <https://toshiba.semicon-storage.com/us/semiconductor/design-development/partnumber/opto.html>
diff --git a/docs/FOG-THREAT-MODEL.md b/docs/FOG-THREAT-MODEL.md
new file mode 100644
index 0000000..f0dde91
--- /dev/null
+++ b/docs/FOG-THREAT-MODEL.md
@@ -0,0 +1,962 @@
+# FOG Threat Model
+
+Status: Draft 0.1
+
+Date: 2026-08-08
+
+## 1. Purpose
+
+This document defines the security and privacy model for the FOG autonomous
+mix network and its native asynchronous services. It identifies protected
+assets, trust boundaries, adversary capabilities, assumptions, required
+properties, non-goals, residual risks, and the evidence required before FOG
+makes public security claims.
+
+FOG is not implemented yet. Every property in this document is therefore a
+design requirement or a validation target, not a statement about deployed
+software.
+
+The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, and MAY describe
+normative requirements in the sense of BCP 14 when they appear in uppercase.
+
+## 2. Scope
+
+This threat model covers:
+
+- the offline `fog-compose` environment;
+- transfer through QR or `FOG-SX` simplex media;
+- the online `fog-client-relay`;
+- entry gateways and three stratified mix layers;
+- directory authorities and signed epoch consensus;
+- KEMSphinx packet processing and replay handling;
+- Noise-protected adjacent-node links;
+- couriers, native services, and capability-addressed storage replicas;
+- asynchronous one-way drops, mailboxes, private messaging, and later group
+ messaging;
+- software distribution, configuration, updates, backups, logs, and
+ operational metrics.
+
+The FOG core does not include SOCKS, VPN, general Internet proxying, clearnet
+exit nodes, web browsing, real-time audio or video, tokenomics, or arbitrary
+user-selected routes. SMTP, NNTP, and foreign Sphinx networks may be reached
+only through separately reviewed edge bridges whose weaker guarantees are
+outside the core anonymity claim.
+
+## 3. System Boundary
+
+The intended high-level path is:
+
+```text
+offline Composer
+ -> QR or FOG-SX simplex transfer
+online blind relay
+ -> temporary entry selected from authenticated consensus
+entry gateway
+ -> mix layer 1 -> mix layer 2 -> mix layer 3
+courier / native service
+ -> capability-addressed storage replicas
+recipient blind relay
+ -> recipient offline Composer
+```
+
+The entry is not one of the three mix hops. The Composer constructs the
+internal KEMSphinx route from authenticated consensus. The blind relay may
+select an entry only from the Composer-approved consensus and temporary entry
+set. The recipient Composer is the only component intended to recover message
+plaintext.
+
+FOG uses three separate cryptographic layers:
+
+1. message-level end-to-end protection between Composers;
+2. KEMSphinx protection for routing and per-hop transformation;
+3. fixed Noise profiles for authenticated adjacent-node transport.
+
+No layer may be treated as a substitute for another.
+
+## 4. Protected Assets
+
+### 4.1 User and message assets
+
+- message plaintext, attachments permitted by the future format, and drafts;
+- long-term identity keys, contact state, ratchet state, recovery material,
+ and backup keys;
+- contact vouchers, reply material, mailbox capabilities, and storage
+ capabilities;
+- the fact that a user is sending, receiving, polling, replying, or remaining
+ idle;
+- sender identity, recipient identity, sender-recipient relationships,
+ conversation membership, and social graph;
+- message length, fragment count, timing, frequency, retry behavior, and
+ conversation lifetime.
+
+### 4.2 Network and operator assets
+
+- authority identity keys, consensus signing keys, and voting state;
+- node identity, Noise, KEMSphinx, replay, storage, and update keys;
+- descriptors, operator-family declarations, topology assignments, epoch
+ state, revocations, and key-overlap state;
+- unreleased topology changes and security-sensitive configuration;
+- replay caches, delay queues, cover-traffic schedules, storage shards, and
+ tombstone state;
+- release signing keys, build provenance, update metadata, and rollback state.
+
+### 4.3 Availability and integrity assets
+
+- consistent authenticated consensus;
+- correct routing and packet transformation;
+- bounded and non-amplifying protocol behavior;
+- eventual delivery within the limits of an asynchronous best-effort system;
+- integrity and freshness of Composer imports and software updates;
+- the ability to revoke compromised identities, nodes, authorities, and
+ releases.
+
+## 5. Security Objectives
+
+### 5.1 Cryptographic objectives
+
+FOG MUST be designed so that:
+
+- only the intended recipient Composer can decrypt message content;
+- recipients can authenticate the claimed sender or contact context according
+ to the selected messaging protocol;
+- alteration, truncation, reordering, substitution, and unauthorized replay of
+ protected message state are detected;
+- a node learns only the routing information needed for its immediate role;
+- packet transformation prevents bitwise input-output linkage at an honest
+ mix;
+- storage replicas cannot decrypt message content or derive stable contact
+ identities from capabilities;
+- compromise of one key purpose does not directly expose keys for another
+ purpose;
+- forward secrecy and post-compromise recovery are provided only if the final
+ reviewed messaging construction supports them and its state transitions are
+ implemented correctly.
+
+FOG MUST NOT claim forward secrecy, post-compromise security, deniability, or
+post-quantum security merely because individual primitives have those labels.
+Those properties apply only after the complete protocol and lifecycle have
+been analyzed.
+
+### 5.2 Metadata privacy objectives
+
+FOG targets the following conditional properties:
+
+- sender anonymity against third parties;
+- recipient anonymity against third parties;
+- sender-recipient relationship unlinkability;
+- route unlinkability across at least one honest mix transformation;
+- resistance to short-term timing and volume correlation;
+- reduced long-term intersection leakage;
+- sender and recipient unobservability when traffic normalization, decoy
+ traffic, padded retrieval, and sufficient anonymity-set activity are all
+ present;
+- unlinkability of successive mailbox locations and storage operations;
+- indistinguishability, within defined traffic classes, of real messages,
+ retries, empty reads, acknowledgments, and cover operations.
+
+These are probabilistic properties, not absolute concealment. Their strength
+depends on measured traffic volume, latency distributions, cover ratio,
+topology, operator independence, user behavior, and adversary position. FOG
+MUST publish the conditions and measured bounds attached to every metadata
+privacy claim.
+
+### 5.3 Availability objectives
+
+FOG provides best-effort asynchronous delivery. It SHOULD tolerate isolated
+node loss, replica loss, delayed packets, duplicate packets, temporary
+partitions, and ordinary churn. It does not promise delivery against a global
+active adversary, sustained distributed denial of service, a failed authority
+quorum, or deliberate destruction of enough storage replicas.
+
+Privacy MUST fail closed where continuing would silently weaken a claimed
+property. Availability failover MUST NOT introduce direct delivery, smaller
+packet classes, bypassed layers, unauthenticated directories, fixed emergency
+routes, or disabled cover traffic without placing the deployment outside the
+affected privacy claim.
+
+## 6. Actors and Trust Boundaries
+
+| Role | May legitimately learn | Must not learn or control alone |
+| --- | --- | --- |
+| Composer | Local plaintext, identity and contact state, selected consensus, constructed route | Other users' plaintext or secrets; unauthenticated network state |
+| FOG-SX receiver | Transfer size class, transfer timing, opaque bundle | Plaintext, contacts, private keys, final recipient |
+| Blind relay | Client-side network context, opaque packets, chosen temporary entry | Plaintext, internal route, final service or recipient |
+| Entry | Previous peer, next mix, packet timing, random short-lived return rendezvous and reply ID | Message plaintext, complete route, recipient identity, durable user account |
+| Mix | Previous hop, next hop, local delay, replay tag | Complete route, endpoint identities, message plaintext |
+| Authority | Node descriptors, operator declarations, votes, epoch state | User messages, mailbox capabilities, unilateral valid consensus |
+| Courier | Requested native operation, replica set or shard information required by protocol | User plaintext, stable user identity, contact graph |
+| Native service | Minimum service-specific opaque state | Network origin, unrelated conversations, Composer secrets |
+| Storage replica | Opaque record, capability-derived location, retention state, access timing | Plaintext, stable mailbox identity, sender-recipient relationship |
+| Observer | Delayed coarse health aggregates | Payloads, packet identifiers, detailed routes, capabilities, fine-grained timing |
+| Edge bridge | Data required by the external protocol | Authority to extend core guarantees to the external network |
+
+No online role is universally trusted. Each role MUST be independently
+deployable and separately keyed. Co-location is a deployment fact, not a
+reason to collapse protocol boundaries or share secrets.
+
+## 7. Adversary Capabilities
+
+FOG analyzes capabilities independently rather than assuming a single linear
+attacker tier. Real adversaries may combine any subset.
+
+### 7.1 Passive observation
+
+The adversary may:
+
+- observe one link, multiple links, the network perimeter, or nearly all
+ Internet links;
+- record packet sizes, directions, timing, connection duration, retransmits,
+ outages, routing changes, and user online periods;
+- retain encrypted traffic for future cryptanalysis;
+- observe hosting providers, AS paths, DNS, time synchronization, software
+ downloads, bridge traffic, and public authority activity;
+- compare observations across hours, epochs, months, and user behavior cycles.
+
+The global passive observer is a target adversary for metadata-resistance
+research and simulation. FOG MUST NOT claim resistance to that observer until
+the complete deployed traffic process, including clients, storage access, and
+cover traffic, has quantitative evidence.
+
+### 7.2 Active network interference
+
+The adversary may drop, delay, reorder, duplicate, replay, corrupt, tag,
+inject, selectively forward, partition, throttle, or burst packets. It may
+manipulate clocks and availability to trigger retries or route changes. It may
+create distinguishable failure patterns and observe the resulting behavior.
+
+The adversary may run malicious clients at scale and may attempt n-1,
+confirmation, blending, flooding, resource-exhaustion, and amplification
+attacks.
+
+### 7.3 Infrastructure compromise and collusion
+
+The adversary may compromise or operate:
+
+- one or more entries, mixes, couriers, services, replicas, observers, or
+ authorities;
+- multiple roles on the same route;
+- multiple nominal operators that secretly form one operator family;
+- hosting providers, hypervisors, management networks, build systems, package
+ registries, or time sources;
+- an authority threshold sufficient to sign malicious consensus;
+- enough storage replicas to destroy or correlate a mailbox;
+- an edge bridge and the corresponding external service.
+
+Compromise includes software exploitation, malicious updates, physical
+access, legal compulsion, bribery, operator mistakes, secret copying, and
+rollback to vulnerable state.
+
+### 7.4 Endpoint and contact compromise
+
+The adversary may compromise the online blind relay, the host running a
+networkless microVM, a physically offline Composer, a transfer device, a
+backup, or a recipient contact. It may use browser, firmware, peripheral,
+DMA, side-channel, evil-maid, removable-media, or supply-chain attacks.
+
+A malicious or compromised contact may send malformed messages, exhaust reply
+material, correlate replies, reveal conversation state, lie about identity,
+or intentionally publish plaintext and relationship metadata.
+
+### 7.5 Cryptanalytic capability
+
+The adversary may exploit weak parameters, nonce reuse, RNG failure, side
+channels, parser differentials, protocol composition errors, implementation
+bugs, downgrade paths, key reuse, and future cryptanalytic advances. A future
+adversary may have practical quantum capability.
+
+FOG assumes reviewed primitives remain secure only within their documented
+parameters. Algorithm names alone are not security evidence.
+
+## 8. Core Assumptions
+
+All security claims depend on the following assumptions:
+
+1. The sender and recipient Composers are not compromised while handling the
+ protected plaintext or key state relevant to the claim.
+2. Users obtain authentic Composer software, trust anchors, and updates.
+3. Cryptographic random number generators provide sufficient entropy.
+4. Selected primitives and libraries are correctly implemented and remain
+ secure for their configured parameters.
+5. At least one mix on a route is honest and its secret state is not exposed
+ during the period relevant to per-hop route unlinkability.
+6. The authority signing threshold is not compromised, and enough honest
+ authorities remain available to produce consensus.
+7. Composer and relay reject stale, rolled-back, malformed, or
+ insufficiently signed consensus.
+8. Declared operator families and infrastructure diversity reflect reality
+ closely enough for path constraints to matter.
+9. Traffic classes, packet geometry, delay distributions, retry behavior, and
+ cover traffic are followed by all honest implementations.
+10. The anonymity set has enough concurrent real and decoy activity for the
+ measured privacy target. A nearly idle network cannot hide activity by
+ declaration.
+11. Users follow the operational profile attached to a claim. A networkless
+ Composer does not help if its secrets are copied to an online system.
+12. External bridges, recipients, and publication systems may disclose the
+ content and metadata that their protocols inherently require.
+
+Violating an assumption MUST narrow or invalidate the corresponding claim. It
+MUST NOT be hidden behind a generic statement that FOG is anonymous.
+
+## 9. Threat Catalogue and Required Responses
+
+### TM-NET-01: Timing and volume correlation
+
+An observer compares ingress and egress timing, size, direction, and burst
+shape.
+
+Required responses:
+
+- fixed packet geometry within consensus-defined traffic classes;
+- randomized independently sampled per-hop delays;
+- normalized client transmission and retrieval schedules;
+- decoy traffic and loops that use the same processing path as real traffic;
+- padded storage operations and acknowledgments;
+- no application-specific route, packet, or retry fingerprint;
+- simulation and trace-based evaluation against realistic observers.
+
+Residual risk: timing defenses reduce correlation advantage but cannot make
+repetitive behavior, low traffic, or indefinite observation harmless.
+
+### TM-NET-02: Long-term intersection and statistical disclosure
+
+An observer records which users are active around repeated sends or receives
+and intersects candidate sets over time.
+
+Required responses:
+
+- cover activity independent of message activity;
+- retrieval schedules that continue across empty and non-empty states;
+- delayed and padded acknowledgments;
+- rotating unlinkable capabilities and reply material;
+- immutable storage-epoch manifests with disjoint intermediate and final
+ replicas under an explicit non-collusion assumption;
+- client guidance that does not encourage deterministic schedules;
+- long-horizon simulation and publication of residual disclosure risk.
+
+Residual risk: intersection leakage exists in all practical systems when user
+behavior and availability are sufficiently distinctive. Repeated polling of
+one empty capability-derived box remains linkable at its final replicas.
+
+### TM-NET-03: n-1 and active confirmation
+
+An active adversary suppresses honest traffic, injects its own packets, or
+forces distinctive bursts so that a target packet becomes isolated.
+
+Required responses:
+
+- decoy-loop health signals and anomaly detection;
+- conservative behavior during unexplained traffic collapse;
+- no immediate deterministic retry after loss;
+- rate and admission controls that limit hostile traffic without creating
+ stable user fingerprints;
+- fault-injection tests that measure isolation and confirmation advantage;
+- documented shutdown or degraded-mode policy when required anonymity
+ conditions disappear.
+
+Residual risk: a sufficiently strong active adversary can deny service and
+may isolate traffic. FOG does not promise availability or anonymity under
+arbitrary global active control.
+
+### TM-NET-04: Replay and duplicate confirmation
+
+An adversary replays packets or reply material and observes repeated effects.
+
+Required responses:
+
+- consensus-bound replay tags and bounded replay windows;
+- replay state that survives ordinary process restarts for the required
+ maximum packet lifetime;
+- single-use reply material with atomic consumption;
+- message-level deduplication that does not emit distinguishable responses;
+- duplicate storage writes and reads handled idempotently;
+- fail-closed behavior if required replay state is corrupt or unavailable.
+
+### TM-NET-05: Tagging and malleability
+
+An adversary modifies a packet and observes whether a later component reacts
+differently.
+
+Required responses:
+
+- a reviewed KEMSphinx profile with authenticated routing data and the
+ documented payload-integrity construction;
+- constant-behavior rejection without detailed remote error oracles;
+- no service action before complete packet and message validation;
+- conformance and mutation tests covering every authenticated field;
+- explicit analysis of SURB-specific tagging and confirmation risks.
+
+### TM-NET-06: Packet, route, and implementation fingerprinting
+
+An adversary distinguishes application, client version, route choice, or
+fallback state.
+
+Required responses:
+
+- one authenticated profile and geometry per authorized traffic class and
+ epoch;
+- identical core processing for all native source applications;
+- no packet autodetection, silent downgrade, or per-packet suite negotiation;
+- complete authenticated consensus view for route construction;
+- bounded version overlap and a clear minimum accepted epoch;
+- rollout tests that prevent minority clients from becoming a fingerprint.
+
+### TM-PKI-01: Sybil nodes and false operator diversity
+
+An adversary obtains many node positions or hides common control behind
+nominally different operators.
+
+Required responses:
+
+- permissioned admission for the initial network;
+- signed operator-family declarations and conflict rules;
+- independent verification of provider, ASN, jurisdiction, ownership, and
+ administration where practical;
+- route rejection when one declared family appears twice;
+- transparent admission, suspension, and revocation records;
+- no claim that permissionless Sybil resistance has been solved.
+
+Residual risk: social and corporate control can be concealed. Governance and
+operator investigation remain part of the security boundary.
+
+### TM-PKI-02: Stale, rolled-back, frozen, split, or equivocated consensus
+
+An adversary gives different network views to clients or prevents updates.
+
+Required responses:
+
+- threshold signatures over canonical consensus bytes;
+- monotonically increasing epochs and explicit validity intervals;
+- current and next keys with bounded overlap;
+- persisted highest-accepted epoch and rollback protection;
+- independent retrieval paths or gossip for equivocation evidence;
+- fail-closed behavior when quorum, time validity, or profile authorization
+ cannot be established;
+- an offline-safe recovery procedure for long-disconnected Composers.
+
+Residual risk: a compromised signing threshold can authorize malicious
+topology. A fully isolated client may not learn that another valid-looking
+view exists without an external consistency mechanism.
+
+### TM-PKI-03: Authority outage or capture
+
+One or more authorities withhold votes, disappear, leak keys, or act under
+compulsion.
+
+Required responses:
+
+- threshold operation with documented safety and liveness limits;
+- offline root and recovery material separated from online epoch keys;
+- rehearsed revocation and authority-replacement ceremonies;
+- deterministic consensus failure behavior;
+- no automatic trust-on-first-use replacement authority.
+
+### TM-ROLE-01: Malicious entry or blind relay
+
+A blind relay observes the local user context. An entry observes the relay
+connection and first mix hop. On a reply, the entry also observes one random
+short-lived rendezvous capability and reply ID while performing the terminal
+KEMSphinx unwrap. Either role may delay, drop, batch, or fingerprint traffic.
+
+Required responses:
+
+- the Composer exports only opaque authenticated bundles;
+- the blind relay cannot alter Composer-approved consensus or the internal
+ route;
+- entry choice is constrained to a small authenticated temporary set;
+- traffic normalization begins before application-dependent variation reaches
+ the entry;
+- entry rotation is by session or epoch, not every message by default;
+- entry return KEMSphinx keys are separate from forward capsule and mix keys;
+- return rendezvous capabilities and reply IDs are random, bounded,
+ single-use, and do not create a durable entry account;
+- clients detect sustained failure without switching to a privacy-bypassing
+ direct path.
+
+Residual risk: a compromised blind relay can associate the local endpoint with
+FOG use and can deny service. Collusion with downstream observation increases
+correlation power.
+
+### TM-ROLE-02: Malicious mix or route collusion
+
+A mix observes adjacent hops and local timing. Multiple malicious mixes share
+their observations or secrets.
+
+Required responses:
+
+- independent operators and family-constrained route construction;
+- per-epoch mix keys with overlap only where required;
+- KEMSphinx transformation and replay detection at every mix;
+- no detailed per-packet logs;
+- cover traffic processed identically to real traffic;
+- compromise simulations for every layer and route position.
+
+Residual risk: if all privacy-relevant hops on a route collude, route
+unlinkability is not guaranteed. Later key disclosure may affect recorded
+packets depending on the final KEMSphinx construction and key-erasure policy.
+
+### TM-ROLE-03: Malicious courier, service, or storage replica
+
+These roles correlate operations, return malformed data, selectively fail,
+exhaust capabilities, or destroy records.
+
+Required responses:
+
+- message-level ciphertext remains opaque through all three roles;
+- rotating capabilities and pseudorandom record locations;
+- courier and replica knowledge separated by protocol design;
+- at least four independently operated replicas for the intended profile;
+- authenticated encrypted replica envelopes;
+- final-replica receipts that distinguish courier acceptance from evidence of
+ durable local commit;
+- uniform treatment of empty reads, hits, misses, retries, and acknowledgments;
+- quorum or erasure behavior that survives defined replica loss;
+- bounded retention, tombstones, quotas, and non-amplifying requests;
+- client verification of every retrieved object before state transition.
+
+Residual risk: enough colluding replicas can correlate or destroy access. A
+malicious service may learn application-level information that the final
+service contract explicitly exposes.
+
+### TM-ENDPOINT-01: Composer compromise
+
+Malware, physical access, a hostile host, firmware, peripheral, or malicious
+update captures plaintext or keys.
+
+Required responses:
+
+- a MicroVM profile with no virtual network interface and a minimal device
+ boundary;
+- a Portable profile with signed immutable media, disabled network and radio
+ drivers, and no automatic internal-disk mounting;
+- authenticated encryption for identities, contacts, drafts, and backups;
+- purpose-separated keys and minimal plaintext lifetime;
+- no secrets in logs, crash dumps, swap, thumbnails, previews, or generic
+ desktop indexing;
+- signed updates with rollback protection and a documented offline ceremony;
+- explicit warning that endpoint compromise defeats local confidentiality and
+ authenticity.
+
+Residual risk: software cannot preserve a secret while an attacker controls
+the component using it. A networkless VM on a compromised host is weaker than
+a physically isolated Composer.
+
+### TM-ENDPOINT-02: Malicious transfer input and bidirectional leakage
+
+A crafted QR, FOG-SX stream, removable device, or optical peripheral exploits
+the parser or creates an unintended return channel.
+
+Required responses:
+
+- one minimal bounded binary format per transfer direction;
+- no generic archives, filesystems, documents, HTML, scripts, or executable
+ content;
+- fixed maximum sizes, allocation limits, canonical encodings, and complete
+ validation before interpretation;
+- fuzzing and property tests for frame, FEC, and bundle parsers;
+- transfer checksum treated only as error detection, never authenticity;
+- inner bundle authentication before any semantic or Composer state change;
+- no automatic acknowledgment or reverse data path in the high-assurance
+ FOG-SX profile;
+- physical inspection that transmit-only and receive-only devices cannot
+ silently reverse direction.
+
+Residual risk: optical, acoustic, electromagnetic, thermal, and human-mediated
+channels may still leak information outside the protocol model.
+
+### TM-ENDPOINT-03: Backup, recovery, and multi-device leakage
+
+Backups or device synchronization copy identity and conversation state into a
+weaker environment.
+
+Required responses:
+
+- backups encrypted and authenticated independently from the live store;
+- backup keys or recovery secrets stored separately from backup ciphertext;
+- explicit key and format version in every encrypted store;
+- tested restore, rotation, revocation, and lost-device procedures;
+- no server-side recovery secret capable of silently impersonating a user;
+- multi-device behavior treated as a separate protocol state machine, not file
+ copying.
+
+### TM-APP-01: Malicious contact and conversation insider
+
+A valid contact sends malformed or adversarial messages, correlates replies,
+publishes shared state, or exploits group membership changes.
+
+Required responses:
+
+- strict authenticated message parsing before rendering;
+- no active content or automatic external resource loading;
+- per-contact rate, size, and state-transition bounds;
+- single-use reply material and safe exhaustion behavior;
+- transcript and membership rules defined by the messaging specification;
+- explicit warning that a storage writer may read and tombstone its own
+ dedicated directional stream when the selected capability construction
+ grants that authority;
+- compromised-contact analysis for direct and group messaging;
+- no promise that encryption prevents a recipient from revealing plaintext.
+
+### TM-OPS-01: Logging and metrics leakage
+
+Operators, attackers, or support workflows recover metadata from logs,
+traces, crash reports, metrics, or dashboards.
+
+Required responses:
+
+- logs MUST NOT contain payloads, contacts, capabilities, message or packet
+ identifiers, full routes, per-packet delay, or fine-grained event timing;
+- production debug logging MUST be disabled;
+- metrics MUST be coarse, delayed, aggregated, thresholded, and reviewed for
+ differencing attacks;
+- node health identifiers MUST not become message-flow identifiers;
+- crash dumps and support bundles MUST be disabled or privacy-scrubbed by
+ default;
+- retention MUST be minimal and explicitly documented.
+
+Residual risk: even aggregate metrics can leak during low-volume periods.
+Metrics may need suppression rather than publication.
+
+### TM-SUPPLY-01: Build, dependency, and update compromise
+
+An attacker inserts malicious code, changes protocol parameters, substitutes a
+binary, compromises a dependency, or rolls a node back.
+
+Required responses:
+
+- pinned reviewed dependencies and recorded provenance;
+- reproducible or independently verifiable release builds where practical;
+- multiple-person release review for security-critical changes;
+- signed canonical release metadata with version and rollback constraints;
+- separate release, authority, node, and user identity keys;
+- secure boot or measured boot where the deployment profile supports it;
+- emergency revocation that does not create an unauthenticated update path.
+
+### TM-CRYPTO-01: Key compromise and lifecycle failure
+
+A key is copied, reused, retained too long, generated weakly, or not revoked.
+
+Required responses:
+
+- a key inventory defining owner, purpose, scope, storage, lifetime, overlap,
+ backup, revocation, and destruction;
+- distinct keys for authority identity, epoch signing, release signing, Noise,
+ KEMSphinx, message identity, ratchet state, storage, capability derivation,
+ and backup encryption;
+- cryptographic randomness from reviewed operating-system facilities;
+- authenticated encrypted storage for long-lived private material;
+- support for old verification keys only for explicit bounded migration;
+- immediate stop of new use after compromise, followed by revocation and
+ replacement;
+- best-effort zeroization without claiming that managed runtimes erase every
+ copy.
+
+### TM-CRYPTO-02: Store now, decrypt later and protocol downgrade
+
+An adversary records traffic for future classical or quantum cryptanalysis or
+forces an older suite.
+
+Required responses:
+
+- suite and geometry authorization bound to signed epoch consensus;
+- protocol identifiers authenticated in every relevant transcript;
+- no silent fallback or operator-selectable downgrade;
+- hybrid post-quantum constructions considered only after full packet,
+ performance, side-channel, and implementation review;
+- bounded suite overlap and a published retirement procedure;
+- claims separated into classical confidentiality, forward secrecy, and
+ post-quantum confidentiality.
+
+Residual risk: no deployed post-quantum construction can eliminate future
+cryptanalytic uncertainty or endpoint compromise.
+
+### TM-AVAIL-01: Flooding, storage exhaustion, and distributed denial of service
+
+An adversary creates clients, packets, reads, writes, fragments, or authority
+traffic at scale.
+
+Required responses:
+
+- strict size, rate, queue, memory, CPU, and concurrency bounds at every
+ boundary;
+- admission or capability controls that avoid stable cross-service identity;
+- non-amplifying error handling and bounded cryptographic work before
+ authentication where possible;
+- storage quotas, expiry, tombstones, garbage collection, and overload policy;
+- graceful shedding that preserves packet-class indistinguishability where
+ possible;
+- simulation and load testing with malicious distributions;
+- no availability claim against sustained global distributed attack.
+
+## 10. Trust Effects of Role Compromise
+
+The expected effect of isolated compromise is summarized below. Collusion can
+combine observations and exceed these bounds.
+
+| Compromised role | Immediate exposure | Property that should remain |
+| --- | --- | --- |
+| Composer | That endpoint's plaintext, keys, contacts, and future local actions | Other users and unrelated conversations |
+| Blind relay | Local endpoint context and FOG-use timing | Message plaintext and internal route secrecy |
+| Entry | Relay address, first-hop traffic, next mix, and short-lived return metadata | Plaintext and final recipient |
+| One mix | Adjacent hops, local timing and local secret state | End-to-end content; route unlinkability if another relevant mix is honest |
+| One authority | Descriptors, votes and ability to withhold | Consensus authenticity without threshold compromise |
+| Courier | Service request pattern and required replica routing | Message plaintext and direct client network identity |
+| One replica | Local opaque records and access timing | Plaintext and complete mailbox stream |
+| Native service | Explicit service-level fields | Network source and unrelated application state |
+| Observer | Approved coarse aggregates | Per-message and per-user activity |
+| Edge bridge | External-side protocol metadata | No extension of core anonymity through that bridge |
+
+The architecture specification MUST refine this table into exact information
+flows and process privileges before implementation.
+
+## 11. Composer Security Profiles
+
+### 11.1 MicroVM profile
+
+The MicroVM MUST have no virtual network interface. Its host integration MUST
+be limited to explicit display, human input, and the smallest feasible
+transfer device. Clipboard sharing, host filesystem mounts, drag-and-drop,
+guest agents, shared memory, audio input, camera input, and USB passthrough
+MUST be disabled unless a later profile specifies and analyzes them.
+
+The MicroVM profile assumes the host can deny service and observe coarse user
+activity. It MUST NOT claim protection from a host that can inspect guest
+memory or replace the hypervisor.
+
+### 11.2 Portable profile
+
+The Portable profile MUST boot from signed immutable media, disable network
+and radio support, avoid automatically mounting internal disks, and keep
+mutable state in an authenticated encrypted store. Boot integrity and update
+verification MUST occur without requiring an unauthenticated online channel.
+
+The high-assurance profile MUST NOT connect its Composer media to an online
+computer. A removable device shuttled between online and offline systems is a
+separate lower-assurance profile.
+
+Both profiles distinguish authenticated local state from freshness. A local
+hash or MAC chain cannot detect replacement of the complete vault, journal,
+and keys by an older coherent copy. A complete rollback-detection claim
+requires a monotonic anchor outside the stated rollback domain. A host-
+controlled virtual TPM is not independent of a hostile MicroVM host.
+
+### 11.3 Import and export boundary
+
+Consensus, contact vouchers, messages, updates, recovery packages, and FOG-SX
+bundles are untrusted until cryptographically verified. Human-readable labels,
+filenames, MIME types, QR presentation, or transport checksums do not confer
+authenticity.
+
+## 12. Key Management Requirements
+
+Every protocol specification MUST provide a key-lifecycle table containing:
+
+- key name and cryptographic purpose;
+- generating component and entropy source;
+- authorized readers and operations;
+- storage and hardware assumptions;
+- epoch, session, message, or long-term lifetime;
+- current and next-key overlap;
+- compromise impact;
+- revocation and recovery procedure;
+- backup policy;
+- destruction and residual-copy limitations.
+
+Private keys MUST NOT appear in source repositories, examples, test fixtures,
+logs, command lines, crash reports, container images, or consensus documents.
+Tests MUST use generated ephemeral fixtures.
+
+Authority, release, and offline recovery keys SHOULD have distinct offline
+storage and ceremonies. Online services MUST receive only the minimum
+short-lived material required for their role.
+
+## 13. Protocol Parsing and Failure Behavior
+
+Every parser MUST:
+
+- operate on a versioned format with an exact maximum size;
+- reject non-canonical, truncated, overlong, duplicate, unknown-critical, and
+ trailing data where the format does not explicitly permit it;
+- bound allocations, nesting, fragment count, decompression, FEC work, and
+ cryptographic work;
+- authenticate before acting on semantic content whenever the protocol allows;
+- avoid detailed remote errors that create parsing or validity oracles;
+- produce deterministic local error classes suitable for testing without
+ logging sensitive input;
+- be covered by conformance vectors, mutation tests, fuzzing, and differential
+ tests where an independent implementation exists.
+
+Core nodes MUST NOT parse generic archives, office documents, HTML, scripts,
+or executable formats.
+
+## 14. Privacy-Preserving Operations
+
+Operational tooling is within the threat model. Deployments MUST define:
+
+- which metrics exist, their aggregation window, release delay, and minimum
+ population threshold;
+- which logs exist, their fields, retention, access control, and deletion;
+- how operators diagnose packet loss without packet-level identifiers;
+- how key ceremonies, node admission, revocation, and emergency changes are
+ audited;
+- how configuration drift and unsafe debug modes are detected;
+- how time synchronization failure is detected without creating a single
+ trusted time source;
+- how backup restore and disaster recovery avoid cloning live identities or
+ replay state.
+
+Public dashboards MUST suppress data when aggregation would reveal the
+activity of a small number of users or nodes.
+
+## 15. Claims FOG Does Not Make
+
+FOG does not claim:
+
+- protection after sender or recipient Composer compromise;
+- guaranteed delivery or resistance to arbitrary denial of service;
+- absolute anonymity or zero metadata leakage;
+- protection when all relevant route positions collude;
+- that a three-node PoC has a meaningful production anonymity set;
+- that encryption prevents recipients from revealing plaintext;
+- permanent storage, guaranteed offline retrieval beyond the active retention
+ window, or deletion from every recipient, backup, journal, and adversarial
+ copy after a tombstone;
+- deniability unless the selected messaging protocol explicitly provides and
+ validates it;
+- post-quantum security based only on the presence of a post-quantum primitive;
+- privacy across SMTP, NNTP, web, or foreign-network bridges equal to the FOG
+ core;
+- protection from all physical, electromagnetic, acoustic, supply-chain,
+ coercion, or future cryptanalytic attacks;
+- that permissioned admission completely prevents concealed Sybil control;
+- that offline operation automatically makes a compromised device safe.
+
+## 16. Validation and Claim Gates
+
+### 16.1 Before the local PoC
+
+Required evidence:
+
+- normative architecture and trust-boundary specification;
+- PKI, wire, packet, profile, messaging, storage, Composer, and FOG-SX
+ specifications;
+- exact packet and message geometry;
+- protocol state machines and key-lifecycle tables;
+- conformance vectors and parser limits;
+- simulator scenarios and measurable privacy metrics.
+
+`FOG-SIMULATION.md` supplies the first deterministic scenario and proxy-metric
+baseline. This gate remains incomplete because formal end-to-end observer
+metrics, replies, retries, storage polling, loop health, queues, congestion,
+user behavior, churn, confidence intervals, and PoC trace calibration remain
+open.
+
+`FOG-LOCAL-POC.md` supplies the first machine-readable local deployment and
+fault-matrix definition. Its strict validator fixes the functional-only claim,
+role separation, pairwise reachability, private state and secret scopes,
+container containment, and required failure cases. The runnable fixture and
+protocol-functional evidence remain open.
+
+### 16.2 Before an operator alpha
+
+Required evidence:
+
+- unit, integration, conformance, fuzz, race, and fault-injection testing;
+- replay, tagging, n-1, flooding, clock, stale-consensus, split-authority,
+ node-loss, and storage-loss tests;
+- simulation using observed or conservatively modeled traffic distributions;
+- at least six mix nodes with two per layer and documented operator-family,
+ provider, ASN, and location diversity;
+- at least three authorities with a 2-of-3 quorum;
+- at least four storage replicas;
+- reproducible deployment and rollback procedures;
+- public documentation that alpha anonymity is experimental.
+
+### 16.3 Before production security claims
+
+Required evidence:
+
+- independent cryptographic and implementation review;
+- resolved high-severity findings and published residual risks;
+- realistic traffic volume and mandatory cover traffic;
+- operational exercises for compromise, revocation, partition, restore, and
+ authority replacement;
+- independently verified release provenance;
+- quantitative claim statements tied to exact software, profile, topology,
+ traffic assumptions, and review version.
+
+Every public claim MUST identify its scope, assumptions, adversary capability,
+software version, network profile, evidence, and known counterexamples.
+
+## 17. Open Security Decisions
+
+The following remain unresolved and block stronger claims:
+
+- activation of a byte-exact reviewed message profile after the structural
+ `FOG-MESSAGING` contract and its non-active PQXDH, Triple Ratchet, and
+ ML-KEM Braid candidate pass implementation and integration review;
+- activation of the non-active SHA3-256 and ML-DSA-65 plus Ed25519 PKI
+ candidates after exact encoding, vectors, separability, implementation, and
+ side-channel review;
+- the exact entry and mutual hybrid post-quantum Noise constructions and
+ reviewed library; X-Wing is only the leading KEM to evaluate;
+- activation of the calculated HPQC split-PRF KEMSphinx candidate after exact
+ dependency, primitive, side-channel, complete-packet benchmark, vector,
+ simulation, and independent review;
+- activation of a byte-exact reviewed storage profile after the structural
+ `FOG-STORAGE` contract and its non-active narrow BACAP/Pigeonhole candidate
+ pass receipt, geometry, implementation, DoS, and integration review;
+- activation of exact Composer vault, platform, bundle, recovery, update, and
+ independent monotonic-anchor profiles after the structural
+ `FOG-COMPOSER` contract passes fault and implementation review;
+- activation of one exact numeric FOG-SX joint profile after its fixed frame,
+ object, padding, parser, no-ACK, and physical-direction contract passes FEC,
+ implementation, license and IPR, resource, vector, hardware, and independent
+ review;
+- cover, loop, delay, retry, retrieval, and acknowledgment distributions;
+- identity compromise, revocation, contact recovery, and multi-device state
+ beyond the identity-only non-resumable recovery baseline;
+- safe anonymous admission and rate control for clients;
+- measurable degraded-mode thresholds and shutdown behavior.
+
+No implementation convenience may silently resolve these questions.
+
+## 18. Residual Risk Statement
+
+Even a correctly implemented FOG network will retain risk from endpoint
+compromise, malicious contacts, long-term statistical disclosure, low traffic,
+operator collusion, concealed common control, active denial of service,
+physical and supply-chain compromise, bridge metadata, coercion, and future
+cryptanalysis. Cover traffic and delay exchange bandwidth and latency for
+reduced observer advantage; they do not create certainty.
+
+FOG's security documentation MUST remain a living record of observed attacks,
+failed assumptions, simulation results, operational incidents, and changed
+claims.
+
+## 19. Primary References
+
+- FOG messaging protocol: `FOG-MESSAGING.md`
+- FOG storage protocol: `FOG-STORAGE.md`
+- FOG Composer protocol: `FOG-COMPOSER.md`
+- FOG simplex transfer protocol: `FOG-SX.md`
+- FOG observability protocol: `FOG-OBSERVABILITY.md`
+- FOG cryptographic suite evaluation: `FOG-CRYPTO-SUITES.md`
+- FOG traffic and topology simulation: `FOG-SIMULATION.md`
+- FOG local Podman PoC: `FOG-LOCAL-POC.md`
+- Danezis and Goldberg, *Sphinx: A Compact and Provably Secure Mix Format*:
+ <https://eprint.iacr.org/2008/475>
+- Piotrowska et al., *The Loopix Anonymity System*:
+ <https://www.usenix.org/conference/usenixsecurity17/technical-sessions/presentation/piotrowska>
+- Infeld et al., *Echomix: a Strong Anonymity System with Messaging*:
+ <https://arxiv.org/abs/2501.02933>
+- Katzenpost mixnet threat model:
+ <https://katzenpost.network/docs/threat_model/>
+- Katzenpost protocol specifications:
+ <https://katzenpost.network/docs/specs/>
+- Noise Protocol Framework:
+ <https://noiseprotocol.org/noise.html>
+
+References inform FOG's attack coverage and terminology. They do not make FOG
+secure by inheritance. FOG requires its own profiles, proofs or analyses,
+tests, simulations, deployments, and reviews.
diff --git a/docs/FOG-WIRE.md b/docs/FOG-WIRE.md
new file mode 100644
index 0000000..1f0964a
--- /dev/null
+++ b/docs/FOG-WIRE.md
@@ -0,0 +1,1246 @@
+# FOG Wire Protocol
+
+Status: Draft 0.1
+
+Date: 2026-08-08
+
+## 1. Purpose
+
+This document defines `FOG-WIRE-1`, the authenticated transport protocol used
+between adjacent online FOG roles.
+
+It refines the following baselines:
+
+- `FOG-THREAT-MODEL.md`, especially `TM-NET-01`, `TM-NET-03`, `TM-NET-04`,
+ `TM-NET-05`, `TM-NET-06`, `TM-PKI-02`, `TM-ROLE-01`, `TM-ROLE-02`,
+ `TM-ROLE-03`, `TM-OPS-01`, `TM-CRYPTO-01`, `TM-CRYPTO-02`, and
+ `TM-AVAIL-01`;
+- `FOG-ARCHITECTURE.md`, especially `ARC-003`, `ARC-004`, `ARC-005`,
+ `ARC-006`, `ARC-007`, `ARC-008`, `ARC-009`, `IF-03`, `IF-04`, `IF-06`,
+ `IF-07`, `IF-08`, `IF-09`, `IF-10`, and `IF-11`;
+- `FOG-PKI.md`, especially consensus-authorized profiles, endpoints,
+ role-specific epoch public keys, monotonic profile state, and hard expiry.
+
+FOG is not implemented. Requirements in this document are protocol targets,
+not statements about deployed security.
+
+The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, and MAY describe
+normative requirements in the sense of BCP 14 when they appear in uppercase.
+
+## 2. Scope
+
+`FOG-WIRE-1` owns:
+
+- the version-1 TCP carrier profile;
+- selection of one exact consensus-authorized Noise profile;
+- responder-only authentication for relay-to-entry links;
+- mutual authentication for node, authority, storage, and observer links;
+- binding of network, epoch, consensus, role, peer, key, and link context to
+ the Noise handshake;
+- handshake and transport framing;
+- fixed-size encrypted records and bounded logical-message fragmentation;
+- command allowlists by link context and direction;
+- per-record cipher-state rekey and bounded fresh handshakes;
+- epoch and profile transition behavior;
+- connection ownership, timeouts, backoff, overload, and failure behavior;
+- key lifecycle, privacy-safe diagnostics, and conformance requirements.
+
+`FOG-WIRE-1` does not own:
+
+- message-level end-to-end encryption;
+- KEMSphinx packet construction, routing, replay tags, or SURBs;
+- the entry submission capsule or return rendezvous;
+- storage capability semantics or replica durability;
+- application acknowledgments, retries, or deduplication;
+- mix delays, route selection, cover rates, or retrieval schedules;
+- consensus construction or profile authorization;
+- local administration, release updates, public mirror HTTP, or Composer
+ transfer formats.
+
+Noise protects one adjacent connection. It does not hide IP endpoints, TCP
+connection existence, timing, direction, duration, or byte volume. It does
+not replace KEMSphinx or end-to-end message encryption.
+
+## 3. Security Goals
+
+FOG-WIRE MUST provide, for one accepted connection:
+
+- authentication of every required online endpoint before application work;
+- anonymity at the Noise identity layer for a blind relay connecting to an
+ entry;
+- confidentiality and integrity of transport records after the handshake;
+- forward secrecy to the extent supplied by the selected reviewed Noise or
+ PQNoise profile and correct erasure of ephemeral state;
+- exact authorization of role adjacency and command direction;
+- authenticated agreement on the network, epoch, consensus, profile, roles,
+ node identifiers, and transport-key identifiers;
+- no silent suite, pattern, carrier, role, or version downgrade;
+- fixed ciphertext length for records within one profile;
+- bounded parsing, allocation, reassembly, cryptographic work, and queues;
+- coarse non-amplifying remote failures;
+- deterministic profile and epoch retirement.
+
+FOG-WIRE does not provide:
+
+- anonymity against an observer who can correlate connection timing or
+ volume;
+- protocol camouflage or censorship resistance;
+- authentication of a blind relay as a stable user or network identity;
+- application-message authenticity or recipient authentication;
+- KEMSphinx replay protection;
+- delivery, liveness, or availability against sustained denial of service;
+- safe operation after compromise of both endpoint processes;
+- post-quantum security merely because one profile contains a post-quantum
+ primitive.
+
+## 4. Protocol Invariants
+
+### WIRE-INV-01: One authenticated profile
+
+Every connection uses exactly one immutable wire profile authorized by the
+accepted consensus. Peers MUST NOT negotiate a list, guess a profile, or fall
+back after failure.
+
+### WIRE-INV-02: One link context
+
+Every connection has exactly one link context that fixes the initiator role,
+responder role, authentication mode, permitted direction, and command
+allowlist.
+
+### WIRE-INV-03: No early application data
+
+Every Noise handshake payload is empty in version 1. No FOG command is sent,
+accepted, buffered as trusted, or acted upon before the handshake completes
+and peer authorization succeeds. Session resumption, PSK resumption, and
+0-RTT application data are forbidden.
+
+### WIRE-INV-04: Consensus is the authority
+
+Operator configuration MAY restrict peers further, but MUST NOT add a peer,
+role, endpoint, key, context, or profile absent from the accepted consensus or
+trusted authority manifest.
+
+### WIRE-INV-05: Fixed encrypted records
+
+All post-handshake records on one connection have the exact ciphertext length
+defined by its profile. Application type and semantic body length MUST NOT
+change that record length.
+
+### WIRE-INV-06: Strict ordered state
+
+Version 1 runs over ordered TCP. Noise transport nonces and cipher-state
+rekeys advance exactly once per successfully sent or received record. A
+missing, duplicated, unauthentic, or out-of-order record terminates the
+connection.
+
+### WIRE-INV-07: Purpose-separated keys
+
+Noise static keys, node identity keys, authority vote keys, KEMSphinx keys,
+entry capsule keys, replica-envelope keys, message keys, queue-sealing keys,
+and release keys are distinct. One key MUST NOT serve two of these purposes.
+
+### WIRE-INV-08: Bounded work before trust
+
+Preface, handshake, frame, record, fragment, connection, and queue work is
+bounded before allocation proportional to attacker-controlled input. A peer
+cannot request an arbitrary algorithm, record size, or reassembly budget.
+
+### WIRE-INV-09: Failure does not widen access
+
+Failure never causes plaintext transport, direct client fallback, layer
+skipping, a new role edge, an older profile, a previous epoch, or a generic
+RPC path.
+
+### WIRE-INV-10: Traffic scheduling is external but mandatory
+
+FOG-WIRE supplies fixed records and a padding record. The authenticated cover
+profile decides when records are emitted. A local keepalive choice MUST NOT
+silently replace or modify that traffic schedule.
+
+## 5. Terminology and Byte Order
+
+Terms used in this specification:
+
+- **wire profile**: immutable mapping from one numeric profile identifier to
+ an exact carrier, Noise protocol name, record geometry, limits, timers,
+ socket behavior, and compatible command-shape registry;
+- **link context**: immutable role adjacency and directional command policy;
+- **preface**: the fixed 32-byte cleartext connection header;
+- **prologue**: the canonical byte string supplied to both Noise handshake
+ states and authenticated by the handshake transcript;
+- **record**: one fixed-size plaintext structure encrypted as one Noise
+ transport message;
+- **logical message**: one command body carried in one or more DATA records;
+- **current consensus**: the accepted consensus valid for new work at the
+ local uncertainty interval;
+- **staged consensus**: a valid future consensus that is not yet active for
+ new work.
+
+All integer fields defined directly by FOG-WIRE are unsigned and encoded in
+network byte order, most significant byte first. Byte arrays have the exact
+declared length. Reserved and padding bytes MUST be zero after decryption or
+when transmitted in cleartext.
+
+TCP is a byte stream. An implementation MUST NOT assume that one write equals
+one read, that one TCP segment equals one FOG frame, or that a partial read is
+an error.
+
+## 6. Version-1 Carrier
+
+The only version-1 carrier is TCP as specified by RFC 9293.
+
+The version-1 carrier profile:
+
+- uses one direct TCP connection between descriptor-authorized endpoints;
+- does not add TLS, DTLS, QUIC, HTTP, WebSocket, SOCKS, a service mesh, or a
+ proxy protocol header;
+- treats IPv4 and IPv6 endpoint forms only as permitted by the active profile;
+- binds the responder key through Noise rather than DNS or X.509;
+- does not trust TCP source address as a cryptographic identity;
+- uses no in-band carrier autodetection;
+- uses no TCP urgent data;
+- treats a half-close as connection termination after bounded output drain.
+
+A future carrier requires a new immutable wire profile and explicit profile
+transition. One port MUST NOT auto-detect TCP FOG-WIRE, TLS, QUIC, or any
+foreign protocol.
+
+FOG-WIRE has a visible fixed preface and does not claim to be
+indistinguishable from unrelated network traffic. Noise ephemeral public keys
+may also be fingerprintable. Deployment documentation MUST state this
+residual risk.
+
+## 7. Wire Profile Registry
+
+Every `wire_profile_id` is a non-zero unsigned 32-bit integer whose meaning is
+permanent. Reusing an identifier for changed bytes or behavior is forbidden.
+
+An exact wire profile definition contains at least:
+
+```text
+[
+ wire_profile_id,
+ wire_version,
+ carrier_id,
+ noise_protocol_name,
+ authentication_mode,
+ permitted_link_context_ids,
+ record_plaintext_size,
+ command_shape_registry_id,
+ maximum_session_records_per_direction,
+ maximum_session_ciphertext_bytes_per_direction,
+ maximum_session_age,
+ preface_timeout,
+ handshake_timeout,
+ fragment_timeout,
+ drain_timeout,
+ reconnect_backoff_profile_id,
+ socket_behavior_profile_id
+]
+```
+
+The registry definition is part of the normative protocol release and is
+identified by an immutable digest in release metadata. Consensus
+`active_profile_ids` authorizes identifiers, not operator-provided profile
+bodies. Implementations MUST reject an authorized identifier they do not
+implement exactly.
+
+The profile fixes one complete Noise protocol name. Pattern, KEM or DH,
+cipher, hash, hybrid combiner, key encoding, handshake message count, and
+handshake message sizes are not independently negotiated.
+
+The initial concrete classical or hybrid post-quantum Noise names and reviewed
+library remain a pre-PoC selection gate. FOG MUST use a published reviewed
+construction and maintained implementation. It MUST NOT create a FOG-specific
+KEM, cipher, combiner, Noise token, or handshake extension.
+
+## 8. Authentication Modes
+
+### 8.1 Entry mode
+
+`ENTRY-AUTH-1` has these semantics:
+
+- the initiator is a blind relay with no static Noise identity in the
+ handshake;
+- the responder is an entry whose exact epoch Noise public key is known from
+ accepted consensus;
+- the initiator authenticates the responder;
+- the responder learns no stable relay identity from Noise;
+- both sides use fresh handshake ephemeral state;
+- all handshake payloads are empty;
+- application work begins only after the complete handshake.
+
+A classical profile MAY realize these semantics with the Noise `NK` pattern
+while mandating an empty first handshake payload. A post-quantum or hybrid
+profile MUST name one reviewed equivalent construction explicitly. Support in
+the abstract Noise framework is not authorization to improvise a conversion.
+
+The entry authenticates each later submission capsule under
+`FOG-SPHINX-PROFILES`. A TCP address, client certificate, username, API token,
+or reusable relay key MUST NOT become a durable FOG user identity.
+
+### 8.2 Mutual node mode
+
+`NODE-MUTUAL-1` has these semantics:
+
+- initiator and responder have distinct role-local static Noise keys;
+- each endpoint knows the exact expected peer public key before connecting;
+- each endpoint proves possession of its corresponding private key;
+- both endpoints use fresh handshake ephemeral state;
+- all handshake payloads are empty;
+- application work begins only after complete mutual authentication.
+
+A classical profile MAY realize these semantics with Noise `KK`. A
+post-quantum or hybrid profile MUST name a reviewed mutually authenticated
+equivalent construction. The peer keys come from the same accepted consensus,
+except authority wire keys, which come from root-certified authority wire-key
+certificates referenced by that consensus.
+
+### 8.3 No optional authentication
+
+Version 1 has no anonymous-to-mutual upgrade, dummy identity, user password,
+bearer token, client certificate, or authentication extension inside the
+handshake. A link context determines one mode before parsing begins.
+
+## 9. Link Context Registry
+
+Version 1 reserves these link contexts:
+
+| ID | Name | Initiator | Responder | Mode | Connection use |
+| --- | --- | --- | --- | --- | --- |
+| 1 | `RELAY_ENTRY` | relay | entry | `ENTRY-AUTH-1` | submission and bounded return traffic |
+| 2 | `ENTRY_LAYER1` | entry | layer-1 mix | `NODE-MUTUAL-1` | forward and reply KEMSphinx packets |
+| 3 | `LAYER1_LAYER2` | layer-1 mix | layer-2 mix | `NODE-MUTUAL-1` | forward and reply KEMSphinx packets |
+| 4 | `LAYER2_LAYER3` | layer-2 mix | layer-3 mix | `NODE-MUTUAL-1` | forward and reply KEMSphinx packets |
+| 5 | `LAYER3_TERMINAL` | layer-3 mix | courier or authorized native service | `NODE-MUTUAL-1` | terminal request and anonymous reply |
+| 6 | `COURIER_STORE` | courier | store | `NODE-MUTUAL-1` | bounded replica operations |
+| 7 | `STORE_STORE` | lower `node_id` store | higher `node_id` store | `NODE-MUTUAL-1` | replica synchronization only |
+| 8 | `NODE_AUTHORITY` | admitted node | authority | `NODE-MUTUAL-1` | descriptor submission only |
+| 9 | `AUTHORITY_AUTHORITY` | lower `authority_id` | higher `authority_id` | `NODE-MUTUAL-1` | PKI protocol objects only |
+| 10 | `ROLE_OBSERVER` | reporting role | observer | `NODE-MUTUAL-1` | approved aggregate reports only |
+
+The numeric ordering rule gives contexts 7 and 9 one canonical connector and
+prevents persistent duplicate connections. Numeric comparison is over the
+complete identifier bytes.
+
+The reply direction MAY use an already authenticated adjacency connection in
+the reverse record direction. It does not authorize a new topology edge. The
+packet profile determines which peer is the next authorized reply hop.
+
+Adding a context or changing its role pair, direction, mode, or command set
+requires a new wire version or immutable profile transition. Operator
+configuration cannot create a custom context.
+
+## 10. Peer Authorization
+
+Before starting a mutual handshake, each side MUST derive an expected peer
+record from one accepted network view:
+
+```text
+ExpectedPeer = (
+ network_id,
+ epoch,
+ consensus_hash,
+ link_context_id,
+ local_role,
+ remote_role,
+ local_identifier,
+ remote_identifier,
+ local_wire_key_id,
+ remote_wire_key_id,
+ local_endpoint,
+ remote_endpoint
+)
+```
+
+For node links, both node descriptors MUST be valid for the selected epoch,
+their effective consensus roles and layers MUST match the link context, and
+their Noise keys MUST have the `node Noise transport` purpose.
+
+For authority links, the authority identifier and dedicated wire public key
+MUST validate through an `AuthorityWireKeyCertificate` signed by the matching
+offline authority root. An authority vote key MUST NOT be used as a Noise
+key.
+
+For `RELAY_ENTRY`, the relay identifier and key identifier are absent and are
+encoded as all-zero values in the prologue. The entry descriptor, role,
+endpoint, profile, and epoch key are still validated exactly.
+
+Authorization MUST be repeated before exposing a completed handshake to the
+role implementation. A peer removed, suspended, revoked, reassigned, expired,
+or no longer adjacent under consensus MUST NOT continue new work merely
+because an old TCP connection remains open.
+
+## 11. Cleartext Preface
+
+Every connection begins with exactly one 32-byte `WirePreface`:
+
+```text
+struct WirePreface {
+ byte magic[8]; // ASCII "FOGWIRE1"
+ uint16 wire_version; // 1
+ uint32 wire_profile_id;
+ uint16 link_context_id;
+ uint64 epoch;
+ uint16 flags; // 0
+ byte reserved[6]; // all zero
+}
+```
+
+The preface is transmitted by the initiator and is not encrypted. The
+responder MUST read all 32 bytes within the profile preface timeout and then:
+
+1. compare `magic` to the exact eight ASCII bytes `FOGWIRE1`;
+2. require `wire_version` equal to 1;
+3. require zero flags and reserved bytes;
+4. require a locally implemented profile authorized for the declared epoch;
+5. require the context to be permitted by that profile and listener;
+6. require the declared epoch to be current or explicitly staged under
+ Section 23;
+7. select exactly one handshake state without probing alternatives.
+
+The preface does not negotiate. The responder sends no selection, supported
+list, retry profile, or downgrade hint. Any failure closes the TCP connection
+without protocol bytes.
+
+## 12. Authenticated Noise Prologue
+
+Both peers construct the exact same byte string before initializing Noise:
+
+```text
+WirePrologue = EncodeFixed(
+ "FOG-WIRE-PROLOGUE-1",
+ WirePreface,
+ network_id,
+ consensus_hash,
+ initiator_role_id,
+ responder_role_id,
+ initiator_identifier,
+ responder_identifier,
+ initiator_wire_key_id,
+ responder_wire_key_id
+)
+```
+
+`EncodeFixed` is concatenation of the exact-width fields in the order shown.
+The domain string is 19 ASCII bytes without a terminator. `network_id`,
+`consensus_hash`, each identifier, and each key identifier use the hash output
+length pinned by the trusted PKI suite. Role identifiers are unsigned 16-bit
+integers. Absent relay identifier and key fields are all zero.
+
+No field is length-prefixed because every width is determined by the trusted
+PKI suite and wire version. Implementations MUST publish byte-exact prologue
+fixtures for every context.
+
+The complete `WirePrologue` is supplied as the Noise prologue input. It is
+authenticated by the resulting handshake transcript but is not secret and is
+not treated as extra key material.
+
+The implementation MUST retain the final Noise handshake hash as a
+connection-local channel-binding value until connection teardown. It MUST NOT
+log, publish, or reuse that value as a cross-session identifier.
+
+## 13. Handshake Framing and State Machine
+
+Each Noise handshake message is carried as:
+
+```text
+struct HandshakeFrame {
+ uint16 noise_message_length;
+ byte noise_message[noise_message_length];
+}
+```
+
+Rules:
+
+- `noise_message_length` MUST be non-zero and at most 65,535;
+- the profile MUST define the exact handshake message count and expected
+ length of every message;
+- a received length different from the profile expectation terminates the
+ connection before proportional allocation;
+- every Noise handshake payload is zero bytes;
+- trailing, extra, duplicated, or out-of-order handshake frames terminate the
+ connection;
+- the complete handshake MUST finish within the profile handshake timeout;
+- a Noise parse, decapsulation, DH, AEAD, key, or authentication failure
+ terminates the connection;
+- no application-specific error is sent during the handshake;
+- ephemeral private state and incomplete cipher state are erased on success,
+ failure, or timeout to the extent supported by the runtime.
+
+The initiator state machine is:
+
+```text
+TCP_CONNECTED
+ -> SEND_PREFACE
+ -> NOISE_HANDSHAKE
+ -> VERIFY_RESPONDER_OR_BOTH_PEERS
+ -> TRANSPORT
+ -> DRAIN_OR_FAIL
+ -> CLOSED
+```
+
+The responder state machine is:
+
+```text
+TCP_ACCEPTED
+ -> READ_AND_VALIDATE_PREFACE
+ -> NOISE_HANDSHAKE
+ -> VERIFY_INITIATOR_IF_REQUIRED
+ -> TRANSPORT
+ -> DRAIN_OR_FAIL
+ -> CLOSED
+```
+
+There is no resumption state and no transition from a failed state back to
+handshake on the same TCP connection.
+
+## 14. Transport Framing
+
+After a successful handshake, each record is carried as:
+
+```text
+struct TransportFrame {
+ uint16 ciphertext_length;
+ byte ciphertext[ciphertext_length];
+}
+```
+
+For one connection, `ciphertext_length` is constant and equals:
+
+```text
+record_plaintext_size + 16
+```
+
+The 16 bytes are the Noise AEAD authentication overhead. The concrete profile
+MUST use a Noise cipher function with this standard overhead.
+
+`record_plaintext_size` MUST be a multiple of 256 between 4,096 and 65,280
+bytes inclusive. Consequently every ciphertext fits the standard Noise
+65,535-byte message limit. FOG-WIRE does not adopt a larger non-standard Noise
+message limit.
+
+A receiver MUST validate the two-byte length against the one expected
+constant before allocating or reading the ciphertext. Zero, short, overlong,
+or profile-mismatched lengths terminate the connection.
+
+TCP split and coalescing are transparent to this framing. One implementation
+MUST interoperate when every framing byte arrives in a separate TCP read and
+when multiple frames arrive in one read.
+
+## 15. Record Plaintext
+
+Every decrypted record has this exact layout:
+
+```text
+struct WireRecord {
+ uint8 record_version; // 1
+ uint8 record_type;
+ uint16 flags; // 0
+ byte message_id[16];
+ uint16 command_id;
+ uint16 command_version;
+ uint32 fragment_index;
+ uint32 fragment_count;
+ uint32 total_length;
+ uint16 fragment_length;
+ uint16 reserved; // 0
+ byte fragment_and_padding[record_plaintext_size - 40];
+}
+```
+
+The 40-byte header is fixed. Version 1 defines:
+
+| `record_type` | Name | Meaning |
+| --- | --- | --- |
+| 0 | `PADDING` | traffic-schedule record, discarded after validation |
+| 1 | `DATA` | one fragment of one allowed logical command |
+| 2 | `CLOSE` | authenticated planned close or fresh-handshake rotation |
+
+Unknown versions, types, flags, commands, command versions, or non-zero
+reserved values are critical errors and terminate the connection.
+
+### 15.1 Padding record
+
+For `PADDING`, every field after `flags`, including all payload bytes, MUST be
+zero. The receiver validates and discards it. It MUST pass through the same
+Noise decrypt, length check, record rekey, accounting, and aggregate metrics
+path as DATA records before semantic discard.
+
+### 15.2 Close record
+
+For `CLOSE`, `command_id` is a coarse close class:
+
+- 0: planned normal close;
+- 1: authenticated fresh-handshake or epoch rotation.
+
+Every other header field after `flags`, except `command_id`, and all payload
+bytes MUST be zero.
+Failure, authentication, parsing, overload, or authorization errors do not
+send a CLOSE reason. They close the socket without protocol bytes.
+
+### 15.3 Data record
+
+For `DATA`:
+
+- `message_id` MUST be a fresh non-zero 16-byte value generated from the
+ operating-system CSPRNG and unique within the connection;
+- `command_id` and `command_version` MUST be allowed for the context,
+ direction, role pair, epoch, and command-shape registry;
+- `fragment_count` MUST be from 1 through 4,096;
+- `fragment_index` MUST be less than `fragment_count`;
+- `total_length` MUST be no greater than 8 MiB and within the lower
+ context-specific limit;
+- `fragment_length` MUST be no greater than
+ `record_plaintext_size - 40`;
+- every non-final fragment MUST fill the complete fragment capacity;
+- the final fragment length MUST equal the remaining declared body length;
+- `fragment_count` MUST equal the unique count implied by total length and
+ fragment capacity;
+- unused `fragment_and_padding` bytes MUST be zero.
+
+Zero-length command bodies use exactly one DATA record with zero fragment
+length and are valid only when the command registry explicitly permits them.
+
+`message_id` is a connection-local reassembly handle, not a capability,
+account, authentication token, delivery identifier, storage key, or
+cross-session replay defense. A narrower command protocol owns idempotency and
+deduplication across reconnects.
+
+## 16. Logical-Message Reassembly
+
+A receiver MAY interleave fragments from multiple logical messages only
+within all profile bounds. It MUST:
+
+1. authenticate and validate each complete record before reading its fields;
+2. reject duplicate fragment indices and inconsistent repeated metadata;
+3. avoid allocation based only on `fragment_count` or `total_length`;
+4. allocate or spool incrementally within a fixed connection budget;
+5. accept at most eight incomplete logical messages per connection;
+6. accept at most 16 MiB of incomplete reassembly state per connection;
+7. expire incomplete messages at the profile fragment timeout;
+8. erase partial bodies on timeout, connection loss, parse failure, or role
+ rejection;
+9. invoke command handling only after exact complete reassembly and final
+ shape validation.
+
+A context profile MAY lower the 8 MiB message limit, eight-message count, or
+16 MiB buffer budget. It MUST NOT raise them in wire version 1.
+
+Implementations SHOULD stream authenticated fragments into bounded
+role-local temporary storage when a command legitimately exceeds the in-memory
+budget. Temporary files MUST be private to the role account, unlinked or
+randomly named without peer identifiers, size-bounded, and deleted on every
+terminal path.
+
+## 17. Command Registry and Direction
+
+Version 1 reserves these command families:
+
+| ID | Command | Body owner |
+| --- | --- | --- |
+| 1 | `PACKET_SUBMIT` | future `FOG-ENTRY-CAPSULE` specification |
+| 2 | `PACKET_FORWARD` | `FOG-SPHINX-PROFILES` fixed KEMSphinx packet |
+| 3 | `PACKET_RETURN` | `FOG-SPHINX-PROFILES` bounded relay return object |
+| 256 | `REPLICA_REQUEST` | `FOG-STORAGE` |
+| 257 | `REPLICA_RESPONSE` | `FOG-STORAGE` |
+| 258 | `REPLICA_SYNC` | `FOG-STORAGE` |
+| 512 | `DESCRIPTOR_UPLOAD` | `FOG-PKI` |
+| 513 | `DESCRIPTOR_RESULT` | `FOG-PKI` |
+| 514 | `AUTHORITY_OBJECT` | `FOG-PKI` |
+| 768 | `AGGREGATE_REPORT` | `FOG-OBSERVABILITY` |
+
+The directional allowlist is:
+
+| Context | Initiator to responder | Responder to initiator |
+| --- | --- | --- |
+| `RELAY_ENTRY` | `PACKET_SUBMIT` | `PACKET_RETURN` |
+| `ENTRY_LAYER1` | `PACKET_FORWARD` | `PACKET_FORWARD` |
+| `LAYER1_LAYER2` | `PACKET_FORWARD` | `PACKET_FORWARD` |
+| `LAYER2_LAYER3` | `PACKET_FORWARD` | `PACKET_FORWARD` |
+| `LAYER3_TERMINAL` | `PACKET_FORWARD` | `PACKET_FORWARD` |
+| `COURIER_STORE` | `REPLICA_REQUEST` | `REPLICA_RESPONSE` |
+| `STORE_STORE` | `REPLICA_SYNC` | `REPLICA_SYNC` |
+| `NODE_AUTHORITY` | `DESCRIPTOR_UPLOAD` | `DESCRIPTOR_RESULT` |
+| `AUTHORITY_AUTHORITY` | `AUTHORITY_OBJECT` | `AUTHORITY_OBJECT` |
+| `ROLE_OBSERVER` | `AGGREGATE_REPORT` | none |
+
+`PACKET_FORWARD` in the reverse record direction is permitted only when the
+packet profile validates the receiving peer as the next hop of an anonymous
+reply. It does not allow arbitrary reverse RPC.
+
+Every narrower specification MUST define exact body bytes, version, maximum
+size, expected padded size class, request-to-response relation, idempotency,
+semantic timeout, and behavior after reconnect. Unknown commands never reach
+role code.
+
+There is no vendor, experimental, operator-private, or generic-RPC command
+range in version 1.
+
+## 18. Command Shapes and Length Privacy
+
+The active `command_shape_registry_id` maps each allowed command to:
+
+- one exact logical body length; or
+- a small ordered set of public padded length classes;
+- an exact record count for each class;
+- a context-specific maximum in-flight count;
+- whether zero-length bodies are valid.
+
+The sender pads the semantic object inside the owning protocol before passing
+it to FOG-WIRE. FOG-WIRE zero-fills only unused space in the last fixed
+record. It does not invent application padding classes.
+
+All native KEMSphinx applications use the same `PACKET_SUBMIT`,
+`PACKET_FORWARD`, and `PACKET_RETURN` shapes for an active packet profile.
+`fog-drop`, `fog-mailbox`, and `fog-im` MUST NOT select distinguishable wire
+sizes.
+
+`FOG-SPHINX-PROFILES.md` defines the exact packet and return bodies. For the
+non-active `FOG-SPHINX-CANDIDATE-MLKEM768-X25519-1`, `PACKET_FORWARD` is
+16,150 bytes and `PACKET_RETURN` is 10,204 bytes. These calculated candidate
+lengths do not authorize the suite. A wire profile paired with it must map each
+body to one deterministic fixed record count and reject any other logical
+length.
+
+The number and timing of records remain observable. A command shape is a
+declared traffic class, not perfect length hiding. The simulator and owning
+protocol MUST evaluate whether a class creates an unacceptable fingerprint.
+
+## 19. Cipher-State Rekey
+
+After encrypting and queueing each complete transport record, the sender MUST
+call Noise `CipherState.Rekey()` on the outbound cipher state exactly once.
+After successfully authenticating, decrypting, and validating the fixed
+ciphertext length of each complete record, the receiver MUST call
+`CipherState.Rekey()` on the inbound cipher state exactly once before
+processing the record semantically.
+
+If authentication fails, the receiver does not advance or retry. It destroys
+both transport cipher states and closes the connection.
+
+Noise rekey changes the current cipher key through a one-way function and does
+not reset the Noise nonce. It does not add a fresh DH or KEM secret. Therefore
+it MUST NOT be described as a replacement for a fresh authenticated
+handshake.
+
+The separate inbound and outbound cipher states are never combined and
+half-duplex Noise mode is forbidden.
+
+## 20. Fresh Handshake and Session Limits
+
+A connection MUST be replaced with a completely new TCP and Noise handshake
+at the earliest of:
+
+- the profile maximum records sent in either direction;
+- the profile maximum ciphertext bytes sent in either direction;
+- the profile maximum session age;
+- activation of a new required epoch key or wire profile;
+- peer role, topology adjacency, endpoint, key, revocation, or authorization
+ change;
+- any uncertainty about cipher-state synchronization;
+- local secret-state restoration or process restart.
+
+Version-1 absolute ceilings are:
+
+| Item | Absolute ceiling |
+| --- | --- |
+| records per direction per session | 2^32 |
+| ciphertext bytes per direction per session | 1 TiB |
+| session age | 24 hours |
+
+Every concrete profile MUST select lower exact values based on cipher bounds,
+cover rate, connection churn, epoch schedule, and measurements.
+
+The connector MAY establish one authenticated replacement in parallel. It
+MUST NOT send new logical messages on the replacement until the handshake and
+authorization complete. The old connection drains only already admitted
+messages for the profile drain timeout, then closes.
+
+Logical-message retry across the replacement belongs to the command owner. A
+transport reconnect MUST NOT silently report application success, replay an
+unknown partial command, or create a second delivery without that command's
+idempotency rule.
+
+## 21. Connection Ownership and Multiplicity
+
+There is at most one active data connection for one tuple:
+
+```text
+(
+ network_id,
+ epoch,
+ wire_profile_id,
+ link_context_id,
+ initiator_identifier,
+ responder_identifier
+)
+```
+
+`RELAY_ENTRY` uses one relay-local connection instance in place of an
+initiator identifier. A relay MAY maintain the small temporary entry set
+permitted by its authenticated cover profile, but the count MUST NOT vary
+immediately with one user message.
+
+One additional authenticated connection MAY exist only as a staged
+replacement. Any other duplicate is closed after authentication without
+moving work to it.
+
+The canonical initiator in Section 9 owns reconnect attempts. A responder
+does not open a reverse substitute connection. Nodes SHOULD maintain required
+adjacency connections independently of application queue occupancy when the
+cover profile requires it.
+
+## 22. Traffic Scheduling, Padding, and Liveness
+
+The active cover profile specifies connection maintenance and a record-emission
+schedule for each privacy-relevant context. It may choose a measured constant,
+Poisson, or other reviewed schedule, but all operators in that profile use the
+same authenticated parameters.
+
+At each scheduled emission opportunity:
+
+- the role sends one queued DATA record allowed by the scheduling policy; or
+- it sends one PADDING record when no eligible DATA record is selected.
+
+DATA arrival MUST NOT cause an undeclared immediate write that bypasses the
+schedule. PADDING MUST NOT be disabled locally while a profile claims traffic
+normalization.
+
+FOG-WIRE defines no `PING` or `PONG`. TCP itself has no sufficient application
+liveness guarantee. Health is inferred from authenticated traffic, socket
+failure, connection age, and separate coarse loop protocols. If a deployment
+enables operating-system TCP keepalive only for dead-resource cleanup, its
+exact settings MUST be profile-bound and it MUST NOT be counted as cover
+traffic or anonymity evidence.
+
+Failure of required cover generation moves the role into the degraded or stop
+state defined by the cover profile. It does not switch to activity-triggered
+records.
+
+The first matrix in `FOG-SIMULATION.md` does not select this schedule. It shows
+that high packet cover can improve simple timing and intersection proxies
+without supplying adequate local mixing at short mean delay. Exact record
+schedules still require queue, liveness, loop, polling, reply, and load models.
+
+## 23. Epoch and Profile Transitions
+
+The preface declares one epoch. The Noise prologue binds the exact consensus
+hash for that epoch. Peers MUST NOT combine a descriptor, key, topology edge,
+profile, or parameter from a different consensus body.
+
+During an authenticated transition:
+
+- a listener MAY accept the current epoch and one preannounced next epoch;
+- a next-epoch connection MAY complete and remain staged before `valid_after`;
+- no next-epoch application work is sent or accepted before `valid_after`;
+- an old profile remains usable only through its signed overlap interval;
+- minimum accepted profile state prevents rollback after promotion;
+- a previous epoch connection stops accepting new work at its exact boundary;
+- bounded draining MUST end before key or consensus hard expiry;
+- expired private keys are erased after the owning protocol's last required
+ grace window;
+- same-epoch consensus conflict freezes new connections and new work.
+
+A listener chooses the exact state directly from the preface and local
+accepted PKI state. It does not try current and old parsers in sequence.
+
+At consensus `valid_until`, new handshakes and new logical messages under that
+consensus stop. Existing connections MAY only perform an explicitly specified
+bounded drain that does not outlive key authorization.
+
+## 24. Timeouts and Reconnect Backoff
+
+Every concrete wire profile defines exact values for:
+
+- TCP connect timeout;
+- 32-byte preface timeout;
+- complete Noise handshake timeout;
+- fixed frame read and write timeout;
+- incomplete logical-message fragment timeout;
+- output drain timeout;
+- maximum session age;
+- reconnect initial delay, multiplier, ceiling, and jitter distribution.
+
+Version-1 absolute maxima are:
+
+| Timer | Maximum |
+| --- | --- |
+| preface | 30 seconds |
+| complete handshake | 60 seconds |
+| incomplete frame | 60 seconds |
+| incomplete logical message | 5 minutes |
+| drain | 30 seconds |
+| reconnect ceiling | 15 minutes |
+
+Timeouts are monotonic-duration measurements, not peer-provided wall-clock
+values. A timeout closes the connection without detailed remote error.
+
+Reconnect uses bounded exponential backoff with CSPRNG-derived full jitter.
+The attempt schedule MUST NOT use node identifiers, message identifiers,
+queue length, or application type as its random seed. Immediate deterministic
+fallback to another route, layer, or older profile is forbidden.
+
+## 25. Backpressure and Resource Limits
+
+Before the local PoC, every role profile MUST set lower operational limits
+within these version-1 absolute bounds:
+
+| Resource | Absolute bound |
+| --- | --- |
+| accepted unauthenticated connections per listener | 1,024 |
+| concurrent handshakes per listener | 256 |
+| active connections per authenticated peer/context | 1 plus 1 staged |
+| encrypted record plaintext | 65,280 bytes |
+| logical message | 8 MiB |
+| fragments per logical message | 4,096 |
+| incomplete messages per connection | 8 |
+| incomplete reassembly bytes per connection | 16 MiB |
+| queued complete logical messages per connection | 1,024 |
+| command versions accepted per command | 2 during signed transition |
+
+Implementations MUST also bound total process connections, file descriptors,
+handshake CPU, KEM decapsulations, per-source unauthenticated attempts, queue
+bytes, write backlog, temporary files, and aggregate reassembly memory.
+
+When a queue is full, the role follows the owning command's shedding policy.
+It MUST NOT allocate without bound, skip authentication, enlarge a packet,
+send an error larger than the triggering record, or route around a required
+layer.
+
+Entry-mode abuse control MAY use coarse short-lived network-source limits and
+valid entry capsules, but MUST NOT create a stable cross-entry user account.
+Safe anonymous admission and rate control remain an explicit open security
+decision.
+
+## 26. Socket Behavior
+
+The immutable socket behavior profile fixes at least:
+
+- TCP no-delay behavior;
+- keepalive enablement and exact cleanup timers if used;
+- send and receive buffer ceilings;
+- user-space write batching;
+- address-family policy;
+- dual-stack binding behavior;
+- connection and accept backlog limits;
+- maximum pending output bytes;
+- graceful close and reset behavior.
+
+Operators MUST NOT tune these settings independently when they affect record
+timing, batching, connection duration, or public traffic claims. The initial
+values require trace measurement on supported operating systems because TCP
+segmentation does not preserve FOG record boundaries.
+
+Proxy-protocol headers, transparent proxy source metadata, TLS termination,
+and service-mesh sidecars are forbidden on core FOG-WIRE listeners. A
+deployment requiring a network proxy is a separate analyzed profile and trust
+boundary.
+
+## 27. Failure Behavior
+
+| Condition | Remote behavior | Local behavior |
+| --- | --- | --- |
+| invalid or unsupported preface | close without bytes | coarse counter |
+| unauthorized epoch, profile, context, role, or endpoint | close without bytes | coarse authorization class |
+| handshake length or timeout failure | close without bytes | coarse handshake class |
+| Noise authentication or decapsulation failure | close without bytes | one aggregate crypto-failure class |
+| transport length mismatch | close without bytes | coarse frame class |
+| Noise record authentication failure | close without bytes | destroy both cipher states |
+| unknown or malformed record | close without bytes | coarse record class |
+| forbidden command or direction | close without bytes | coarse policy class |
+| reassembly bound or timeout | close without bytes | erase partial state |
+| queue saturation after authentication | owning protocol's uniform bounded outcome or close | aggregate overload class |
+| planned rotation | one fixed CLOSE record if schedule permits | bounded drain and fresh handshake |
+| TCP loss or half-close | no protocol error | erase partial state and back off |
+
+Peers never receive parser offsets, expected keys, supported profiles,
+consensus hashes, role policy, capacity, queue depth, or cryptographic error
+details.
+
+The implementation is not required to make all local computation paths
+constant-time with respect to public invalid framing. Cryptographic libraries
+MUST provide their required side-channel protections, and remotely observable
+failure behavior MUST remain non-amplifying and free of detailed oracles.
+
+## 28. Logging and Metrics
+
+FOG-WIRE MUST NOT log or export:
+
+- plaintext or ciphertext record bodies;
+- entry capsules or KEMSphinx packets;
+- `message_id`, Noise handshake hash, traffic key, ephemeral key, or private
+ key material;
+- per-record timestamps or direction traces;
+- queue contents, logical-message hashes, capabilities, or reply material;
+- source IP addresses for anonymous relay-to-entry sessions in persistent
+ application logs;
+- detailed handshake failure stages associated with one remote endpoint.
+
+Role-local debugging MAY use coarse enumerated failure classes in a protected
+short-retention log, without input bytes or secret values. Claim-bearing
+profiles disable packet and record tracing.
+
+Metrics are delayed aggregates over declared windows and minimum populations.
+Allowed examples include total completed handshakes by context, aggregate
+failure class, coarse connection age bucket, aggregate queue occupancy bucket,
+and total padding-to-data ratio. The observer interface receives aggregates,
+not event streams.
+
+## 29. Key and Secret Lifecycle
+
+| Key or secret | Generator | Authorized use | Lifetime and overlap | Compromise response | Backup |
+| --- | --- | --- | --- | --- | --- |
+| Node Noise epoch private key | owning node OS CSPRNG | one node role and authorized adjacent links | profile-bounded current key, staged next key, exact grace only | revoke key or node, stop new handshakes, rotate | no routine backup |
+| Entry Noise epoch private key | entry OS CSPRNG | authenticate `RELAY_ENTRY` and authorized node links | profile-bounded current and staged next | revoke entry key, stop sessions, rotate | no routine backup |
+| Authority wire private key | authority wire service OS CSPRNG or controlled ceremony | authority mutual links only | root-certified bounded interval, staged next key | root-signed revocation and replacement | SHOULD NOT restore into a concurrent service |
+| Handshake ephemeral private state | connection endpoint OS CSPRNG | one Noise handshake | until handshake completion or failure | close connection, erase state | none |
+| Noise transport cipher states | Noise handshake `Split()` | one direction of one connection | until close or fresh handshake | destroy connection state and reauthenticate | none |
+| Reassembly message identifier | sending role OS CSPRNG | one logical message within one connection | until completion or timeout | discard partial message | none |
+| Queue-sealing key | owning role local secret facility | local queued ciphertext at rest | deployment-rotated, independent of Noise | quarantine queue, rotate, discard unverifiable state | profile-specific encrypted backup |
+
+Static private keys MUST be readable only by the one role service that owns
+them. They MUST NOT appear in environment templates, command arguments,
+container images, shared volumes, logs, crash dumps, examples, test fixtures,
+or support bundles.
+
+Best-effort zeroization is required for ephemeral, cipher-state, and partial
+plaintext buffers. Documentation MUST NOT claim complete erasure where the
+language runtime, allocator, kernel, swap, hibernation, or hardware cannot
+guarantee it.
+
+## 30. Implementation Requirements
+
+An implementation MUST:
+
+- use a maintained reviewed Noise or PQNoise library;
+- use the operating-system CSPRNG for static keys, ephemeral state, message
+ identifiers, and jitter;
+- keep protocol framing separate from role command parsing;
+- enforce all limits before proportional allocation;
+- use checked integer arithmetic for lengths, counts, and record totals;
+- reject trailing bytes and unknown-critical values;
+- authenticate complete records before semantic parsing;
+- prevent one role package from importing another role implementation;
+- expose one typed context-specific command interface, not raw generic RPC;
+- disable core dumps and secret-bearing panic or exception output;
+- hold static private keys in the minimum role-local protected facility;
+- destroy connection state on every authentication or synchronization error;
+- keep the Composer implementation free of FOG-WIRE listeners and sockets.
+
+The protocol implementation MUST NOT:
+
+- implement cryptographic primitives or hybrid combiners locally;
+- let configuration specify an arbitrary Noise protocol string;
+- use a shared transport key for multiple nodes or roles;
+- retry decryption with old keys or profiles;
+- accept a DNS result, TCP source, or TLS certificate instead of PKI key
+ validation;
+- expose a generic byte tunnel to applications;
+- compress records or logical messages at the wire layer;
+- silently fragment an over-limit command;
+- persist session cipher state for resumption.
+
+### 30.1 Required module boundaries
+
+The future implementation keeps these responsibilities independently
+testable:
+
+```text
+role executable and role package
+ -> TCP listener or connector adapter
+ -> FOG-WIRE session state machine
+ -> profile and link-context authorization
+ -> pure preface, prologue, frame, record, and fragment codecs
+ -> reviewed Noise or PQNoise library
+```
+
+The pure codecs MUST be testable without opening a socket or starting a role.
+The session state machine owns no role database and invokes only a typed
+context-specific command boundary after complete validation. The TCP adapter
+owns socket IO but does not parse role command bodies. Role handlers own
+semantic commands but never access Noise cipher state or unvalidated record
+bytes.
+
+Profile registry, framing, session, and command-shape code MUST NOT be placed
+in a generic `utils` package. Role packages MUST NOT call each other to bypass
+the wire contract or share one transport singleton. Separate executables are
+justified by the established security and state-isolation boundaries, not by
+independent feature scaling.
+
+## 31. Conformance and Adversarial Tests
+
+Before the local PoC, FOG-WIRE MUST have tests for:
+
+- byte-exact preface encoding and every rejected field variation;
+- byte-exact prologue construction for every context and PKI hash length;
+- entry responder authentication with no relay static identity;
+- mutual node and authority authentication;
+- wrong network, consensus, epoch, context, role, node, endpoint, key, and
+ profile binding;
+- empty handshake payload enforcement and attempted early application data;
+- handshake messages at expected, short, long, zero, and 65,535-byte bounds;
+- TCP reads split at every byte boundary and coalesced across multiple frames;
+- fixed ciphertext length and standard Noise maximum enforcement;
+- every record type and zero-reserved or zero-padding rule;
+- unknown record, command, command version, close class, and direction;
+- valid single- and multi-fragment reassembly;
+- duplicate, missing, reordered, inconsistent, expired, excessive, and sparse
+ fragments;
+- exact 8 MiB, 4,096-fragment, 8-message, and 16 MiB boundaries;
+- per-record outbound and inbound rekey synchronization;
+- authentication failure before and after a rekey boundary;
+- fresh-handshake record, byte, age, epoch, topology, and profile boundaries;
+- current and next epoch staging with no early forwarding;
+- old-profile retirement and rollback refusal;
+- duplicate connection collision and one staged replacement;
+- queue saturation, slow reads, slow writes, half-close, reset, and timeout;
+- reconnect backoff and jitter bounds under repeated failure;
+- listener floods and expensive-handshake concurrency limits;
+- log and metrics schema rejection of prohibited fields;
+- parser mutation, coverage-guided fuzzing, differential framing tests, race
+ tests, and allocation tests;
+- firewall validation for every link context and forbidden role edge.
+
+Tests generate ephemeral private fixtures at runtime. Private keys MUST NOT be
+committed as example or conformance data. Public canonical framing fixtures
+MAY be committed when they contain no secret material.
+
+Independent implementations MUST consume the same public framing and
+transcript-binding corpus before interoperability is claimed.
+
+## 32. Claim Gates
+
+### 32.1 Functional PoC
+
+The local PoC MUST demonstrate:
+
+- one fixed reviewed Noise profile;
+- responder-only relay-to-entry and mutual node authentication;
+- complete traversal of entry and three mix layers;
+- fixed records, padding records, fragmentation, and strict command policy;
+- per-record rekey and bounded fresh handshakes;
+- current and next epoch transition;
+- malformed, unauthorized, flooded, and disconnected peers;
+- no multi-role key, state, account, or writable-volume sharing.
+
+This demonstrates functional correctness only. It does not demonstrate a
+production anonymity set or global-observer resistance.
+
+`FOG-LOCAL-POC.md` fixes the container and network boundary for this gate. It
+uses one internal pairwise network per permitted data-plane adjacency, no host
+ports, and no shared role state. Its current validated plan is not a FOG-WIRE
+implementation and deliberately contains no invented wire profile or port.
+
+### 32.2 Operator alpha
+
+Alpha additionally requires:
+
+- fixed reviewed hybrid post-quantum or explicitly documented classical
+ profile selection;
+- interoperability between independently built endpoints;
+- fuzz, race, load, fault, and side-channel review results;
+- measured TCP record segmentation and timing on supported systems;
+- measured handshake cost and anonymous-entry flood behavior;
+- six independently operated mixes and profile-conformant cover scheduling;
+- rehearsed key compromise, revocation, epoch transition, and rollback tests;
+- public residual-risk documentation for visible endpoints and traffic.
+
+### 32.3 Production transport claims
+
+Production claims additionally require:
+
+- independent protocol and implementation review;
+- reviewed library and dependency provenance;
+- published concrete suite, geometry, limits, and conformance results;
+- verified erasure and crash behavior within stated platform limits;
+- sustained adversarial load and resource-exhaustion testing;
+- evidence that profile rollout does not create persistent minority
+ fingerprints;
+- claim wording that distinguishes link confidentiality, forward secrecy,
+ post-quantum assumptions, and metadata privacy.
+
+## 33. Requirements Traceability
+
+| Requirement | FOG-WIRE control |
+| --- | --- |
+| `TM-NET-01` | fixed records, command shapes, profile-bound scheduling, padding records |
+| `TM-NET-03` | bounded retries, no bypass, cover-profile failure gate |
+| `TM-NET-04` | ordered Noise nonces, no resumption, command-owned cross-session deduplication |
+| `TM-NET-05` | authenticated records, strict failure, no action before validation |
+| `TM-NET-06` | immutable profiles, exact context, no negotiation or autodetection |
+| `TM-PKI-02` | epoch and consensus binding, monotonic profile transition, hard expiry |
+| `TM-ROLE-01` | anonymous relay mode, authenticated entry, no durable relay account |
+| `TM-ROLE-02` | exact layer adjacency, mutual node authentication, no layer skip |
+| `TM-ROLE-03` | courier/store contexts, command separation, fixed replica shapes |
+| `TM-OPS-01` | prohibited log fields, delayed aggregate metrics |
+| `TM-CRYPTO-01` | purpose-separated keys, lifecycle table, fresh handshakes |
+| `TM-CRYPTO-02` | consensus-authorized exact Noise name, no fallback, bounded overlap |
+| `TM-AVAIL-01` | strict frame, fragment, handshake, connection, queue, and CPU bounds |
+| `ARC-003` | no data-plane bypass or new failure edge |
+| `ARC-004` | Noise limited to adjacent transport protection |
+| `ARC-005` | peers and profiles derived from one complete accepted consensus |
+| `ARC-006` | fixed records and application-independent packet commands |
+| `ARC-007` | one private-key owner and one purpose |
+| `ARC-008` | exact versioned framing and absolute parser limits |
+| `ARC-009` | coarse non-amplifying remote failure |
+| `IF-03` | authenticated bounded descriptor command |
+| `IF-04` | authenticated authority object command |
+| `IF-06` | anonymous relay initiator, authenticated entry, fixed submission command |
+| `IF-07` | mutually authenticated exact layer adjacency |
+| `IF-08` | fixed authenticated layer-3 to terminal transport |
+| `IF-09` | dedicated courier/store and store/store contexts |
+| `IF-10` | reverse-direction packet only over authorized adjacency |
+| `IF-11` | aggregate-only observer command |
+
+## 34. Open Pre-Implementation Selections
+
+The version-1 protocol structure is fixed, but these selections block daemon
+implementation:
+
+- the exact reviewed classical or hybrid post-quantum Noise protocol names;
+- the reviewed Noise or PQNoise library and supported implementation language;
+- X-Wing is the leading KEM to evaluate, but no exact FOG entry or mutual
+ post-quantum handshake profile is selected;
+- exact `wire_profile_id` assignments and immutable registry digests;
+- record plaintext size and command-shape pairings;
+- fresh-handshake record, byte, and age thresholds;
+- concrete timeouts, reconnect distribution, and socket behavior profile;
+- lower role-specific connection, queue, CPU, and memory limits;
+- packet, PKI, and observer command body specifications, plus byte-exact
+ `FOG-STORAGE` command-to-record mappings;
+- cover-record schedules and degraded-mode thresholds from simulation;
+- safe anonymous entry admission and flood-control policy;
+- authority wire-key certificate rollout and revocation ceremony.
+
+Implementations MUST NOT resolve these selections through undocumented local
+defaults. Each selected value becomes an immutable reviewed profile with test
+vectors and a signed transition path.
+
+## 35. References
+
+- FOG threat model: `FOG-THREAT-MODEL.md`
+- FOG architecture: `FOG-ARCHITECTURE.md`
+- FOG public key infrastructure: `FOG-PKI.md`
+- FOG storage protocol: `FOG-STORAGE.md`
+- FOG cryptographic suite evaluation: `FOG-CRYPTO-SUITES.md`
+- FOG traffic and topology simulation: `FOG-SIMULATION.md`
+- FOG local Podman PoC: `FOG-LOCAL-POC.md`
+- Noise Protocol Framework:
+ <https://noiseprotocol.org/noise.html>
+- Katzenpost mix network wire protocol:
+ <https://katzenpost.network/docs/specs/wireprotocol/>
+- Post Quantum Noise:
+ <https://eprint.iacr.org/2022/539>
+- CFRG X-Wing KEM Internet-Draft:
+ <https://datatracker.ietf.org/doc/draft-connolly-cfrg-xwing-kem/>
+- RFC 9293, Transmission Control Protocol:
+ <https://www.rfc-editor.org/rfc/rfc9293.html>
+- RFC 8174, Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words:
+ <https://www.rfc-editor.org/rfc/rfc8174.html>
+
+These references inform Noise handshake semantics, standard message bounds,
+rekey behavior, TCP stream framing, post-quantum construction review, and
+adjacent mix-link experience. They do not make a concrete FOG profile secure
+without exact selection, conformance testing, operational measurement, and
+independent review.