# 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.
