Hibernation replicates *.db only, so a sidecar's identity (its private key) does not survive a move Issue open
Migrated from github.com/carlosframework/platform issue #191, opened 2026-08-14. GitHub issues are closed for this repo; see AGENTS.md, "Work is tracked on amadan, not GitHub".
Still outstanding: Hibernation replicates *.db only, so a sidecar's identity does not survive a box move.
---
The gap
internal/ops/litestream.go builds the replica set by globbing filepath.Join(dataDir, "*.db"). That is the whole of what parks in S3.
Everything else in /data/<host>* is box-local: <host>.env, <host>-sidecar.env, and — the one that matters — whatever state a sidecar persists. The activator's own contract makes that state load-bearing: HasSidecar is defined as <host>-sidecar.env existing, and StartSidecar execs <binary> sidecar run under it (internal/activator/backend_exec.go).
For Eleven, the sidecar is an E2EE member. Its session file holds the bot's private key. So an instance that hibernates and is rehydrated on a different box comes back:
- with no sidecar env file →
HasSidecarfalse → no bot at all, silently; or, if the env file is restaged, - with no session → the sidecar tries to self-provision from its one-time invite → the invite is already spent → it cannot rejoin.
Either way the bot is gone, and the thread keys wrapped to its public key are now wrapped to a key nobody holds. The messages stay readable to every human member; the bot's own view of them does not come back. Nothing warns.
Why I'm filing it here rather than on the app
Two honest readings, and I think this one is the platform's:
- Platform: hibernation moves an instance between boxes and defines what travels with it. Defining that as "the SQLite files" is a reasonable v1, but the sidecar co-spawn is a first-class platform feature whose state the same platform then declines to move. Those two decisions are inconsistent with each other.
- App: Eleven could keep bot identities in the instance database instead of beside it, and get replication for free.
(2) is a real fix and we may do it regardless — it is strictly better for us. But it only fixes apps that know to do it, and the platform currently gives no signal that non-DB state is ephemeral. An app author reading "/data/<host> is your instance's directory" has no way to learn that only some of it survives.
What would help, roughly in order of cheapness
- Say so. Document that only
*.dbtravels, in the hibernation design and wherever the sidecar contract is described. That alone would have made us design differently. - Refuse quietly-broken states. A host that wakes with a sidecar env file but no prior state could at least log that it is provisioning fresh, rather than doing it silently.
- Replicate a declared state path. An app declaring, say,
data: { replicate: "app" }(the capability vocabulary already has adataslot) could have/data/<host>-<app>/travel with the database.
Not urgent for us — CARLOS spaces have no sidecar yet, precisely because there is no way to stage one from off-box (separate issue). But it should be settled before the first bot-bearing space hibernates, because the failure is silent and the credential is unrecoverable.