7.2 KiB
Offline Mode and Reintegration
The mesh keeps running when the central server is unreachable. This document is the reference for how that works in detail.
The central plugin is network-plugin-server-bridge, governed by NET-31..NET-34 and NET-56.
Detection (NET-31)
Tier 0 hosts maintain a persistent WebSocket to the central server with bidirectional heartbeats. The server-bridge declares the server dead within 2× the heartbeat interval after the last successful heartbeat. Standard verification rules apply (re-ping through alternate paths; consensus among multiple Tier 0 hosts) to avoid declaring a dead server on a transient blip.
Autonomous operation (NET-32)
Once the server is declared dead, the mesh transitions to autonomous mode. The transitions are:
| Subsystem | Online → Offline |
|---|---|
| Token grace periods | extended by configurable factor (e.g., expiresAt += 24h) |
| New mesh / session creation | paused; new requests rejected |
| New peer admission | requires a still-valid pre-issued CapabilityToken; raw onboarding paused |
| Audit-log finalisation | local append continues; finalisation deferred |
| Audit-log replication to server | buffered |
| Cross-mesh trust | existing MeshTrustTokens remain valid; new ones cannot be issued |
| Topology, failover, elections | unchanged — fully client-side |
| Drive read/write | unchanged — every operation is signed by drive identity, verifiable later |
The bus emits server:disconnected so plugins can react. Most plugins do nothing — they don't depend on the server. Plugins that do depend on the server (server-bridge, auth, audit-mesh) flip into offline mode.
What gets buffered (NET-32)
Three buffer streams, all in local storage (typically OpfsStorage in the browser, FileStorage on a server peer):
- Pending audit-log entries — every signed log entry that would have been finalised by the server.
- Pending token-issuance requests — operations the user attempted that need a server-signed token.
- Pending mesh state deltas — bitpacker-encoded registry/topology deltas that the server would have authoritatively reconciled.
All three streams are append-only and signed by the issuing peer. Storage is bounded; on overflow, the oldest non-CRITICAL entries are dropped first. CRITICAL entries are never dropped — if the buffer is full of CRITICAL, the system surfaces an error and refuses to accept more until the user clears space (or the server returns).
Reconnection (NET-33)
When the server-bridge re-establishes the WebSocket, the reconciliation pipeline runs:
1. Handshake
Server-bridge sends its mesh-bridge identity and the highest seq the server has.
Server replies with the seq it expects.
2. Replay buffered entries in seq order
For each:
a. Server verifies Ed25519 signature against the issuing peer's pubkey.
b. Server checks for conflicts with other partitions' replays.
c. On accept: append to authoritative log, advance seq.
d. On conflict: invoke partition merge protocol (NET-80, NET-81).
3. Process pending token requests
For each queued request:
a. Re-validate authorization (the issuer may no longer be eligible).
b. Issue server-signed token.
c. Notify the requesting peer via bus.
4. Reconcile state
Server broadcasts `state:reconciled { meshState, sessionStates, ... }`.
Each plugin updates its local view to match.
5. Hosting transition (model-dependent)
In SERVER_TO_CLIENT_FAILOVER, the acting Tier 0 demotes; server resumes Tier 0.
In CLIENT_WITH_SERVER_BACKUP, the user remains Tier 0; the server returns to its
participant role.
6. Bus emits `server:reconnected` and `mesh:reconciled`.
Suspended operations (new mesh creation, etc.) resume.
The replay is idempotent: replaying an already-finalised entry is a no-op (the server tracks (peerId, seq) to dedupe). This means a flaky reconnect that drops mid-replay can simply retry from the last acknowledged seq.
Conflict resolution
Two partitions running autonomously can produce conflicting state. Examples:
- Both elected a different acting Tier 0.
- Both wrote different state to the same path.
- Both admitted a peer the other doesn't know about.
The merge protocol (NET-81) reconciles using the partition QuorumResolver strategy (NET-80) — size, performance, age, or hybrid. Whichever partition wins becomes the authoritative source; the other partition's peers rejoin (NET-82).
For state-level conflicts that don't involve elections, network-plugin-state reconciliation runs (NET-42) with one of five strategies: latest-wins, remote-wins, local-wins, deep-merge, or custom. The strategy is configurable per state path via PathStrategyRegistry.
Audit-log compaction (NET-39)
After reintegration, the audit log can grow unbounded. Compaction folds old entries into signed checkpoints:
checkpoint {
seqRange: [from, to],
stateSnapshot: bitpacker-encoded snapshot at seq=to,
hostSignature: Ed25519 over (seqRange ‖ stateHash),
}
Replicas use the latest checkpoint to skip the entire prefix when bringing up a fresh peer. The full history remains available for forensic queries; the on-the-wire replay path skips it.
Hosting-model interactions
| Model | What happens at server-down | What happens at server-up |
|---|---|---|
PURE_CLIENT |
No-op — there's no server to lose. | No-op. |
SERVER_BASED |
Mesh stops. Operations queue locally; users see "offline" UI. | Replay queue drains; mesh resumes. |
SERVER_TO_CLIENT_FAILOVER |
Election promotes Tier 1 → acting Tier 0. Mesh continues with full operations except new-token issuance. | Acting Tier 0 demotes; server resumes. Buffered log replays. |
CLIENT_WITH_SERVER_BACKUP |
User remains Tier 0; mesh continues normally. The server is "missing" but it wasn't authoritative anyway. | Server rejoins as participant. Buffered log replays. |
The mesh token (NET-29) carries the model, so the server-bridge knows which transitions to run.
Common pitfalls and how the design avoids them
| Pitfall | Avoidance |
|---|---|
| Replay stuck on a single bad entry | Server processes entries individually; rejects-but-continues. |
| Buffer overflow loses history | CRITICAL entries are never dropped. Surface error before silent loss. |
| Two acting Tier 0s in different partitions both finalising tokens | Tokens issued in autonomous mode have a special bit set; on merge, one partition's tokens are voided per the quorum strategy and re-issued. |
| Clock drift causes apparent expiry mid-outage | extendedExpiresAt is computed from the peer's clock, not the server's, so lack of server time doesn't cause spurious expiry. |
| Long outage ⇒ everyone's CapabilityToken expires | Grace-period extension is automatic; if the outage exceeds the configured maximum, the mesh degrades to read-only. |
Reading further
topology-and-failover.md— election + Tier-0 promotion.security-and-tokens.md— the cryptographic chain that makes replay safe.plugins-catalog.md—network-plugin-server-bridge,network-plugin-audit-mesh,network-plugin-partition.