# Identity, Lifecycle & Recovery

Putting a room's identity, membership, and keys **in the link** buys an account-free experience — but a bearer
link is easy to copy, screenshot, sync, log, lose, or leak, and the hard questions are never the initial key
exchange; they're **removal, rotation, recovery, and what the platform can still see.** This page answers those
directly, and marks precisely **what is shipped vs. designed** — because for a privacy product, overclaiming the
lifecycle is worse than admitting a gap.

Two layers carry the answers: the **cryptographic primitives** (mostly shipped — see
[The Verified Room](https://docs.witbitz.chat/docs/verified-rooms.md) and [the double blind](https://docs.witbitz.chat/docs/the-double-blind.md))
and the **Witbitz Companion**, a device-side runtime that moves keys off the copy-around URL and into a place a user
controls (roadmap — §9).

---

## The seven questions

### 1. What happens after a member is removed?
Two halves, and they ship on different timelines.

- **Writes — cut now (shipped).** A revoked member is on the Space's `revoked` list (sealed in the config); the turn
  op rejects their next turn `403` even with a valid credential. They can no longer post.
- **Reads — cut by re-keying (designed for Spaces; live in the Bridge).** Today the ledger is sealed under one
  long-lived room key `mk` that the removed member still holds, so removing them does **not** by itself stop them
  *reading*. The fix is an **epoch re-key**: mint a fresh key for the remaining member set and seal new content only
  to them. This is **already live in the Bridge** (`bridgeMembership` — every join/revoke opens a new epoch) and is
  the designed path for the async Space; it is not yet ported to the single-Space ledger. **We state this plainly
  rather than imply removal is instant on both halves.**

### 2. Can a removed member decrypt historical content?
Content they could already read, they retain — a re-key protects the **future**, not the past (whoever held `mk`
saw what they saw). There is no cryptographic un-see. Where this matters, the pattern is to compartmentalize by
epoch from the start so a member only ever held the keys for their tenure.

### 3. Can they receive future entries?
After an epoch re-key on removal: **no** — new entries are sealed to the new epoch key, which they were not given
(forward secrecy). This is the Bridge's behavior today; bringing it to the single-Space ledger is the work in §1.

### 4. How are links / keys rotated?
Rotation = **open a new epoch, re-seal forward, hand the remaining members the new key.** The Bridge does exactly
this on every membership change. The friction a *link* adds — "rotating means re-sharing a URL" — is what the
**Companion** removes: the new epoch key is delivered to a member's **device**, not pasted into a new link (§9). On
the pure-link path today, rotation means issuing new member links; per-member **grants are already independent and
expiring** ([verified rooms §3.1](https://docs.witbitz.chat/docs/verified-rooms.md)), so one member rotates without
disturbing the others.

### 5. How does a user recover after losing every device?
**Today: they don't — by design.** The room key lives in the link/device and there is **deliberately no operator
recovery key** (that is the whole point of the double blind — an operator key would be a backdoor). So "lose every
copy, lose the data" is the honest current tradeoff. The **roadmap** answer is *user-held* recovery, never
operator-held: a recovery code the user stores, and/or **k-of-n social recovery** (the same Shamir split the couple
key already uses — a threshold of the user's own guardians reconstitutes the key), with the **Companion** as the
place that safeguards and syncs those shares across the user's own devices. Recovery moves to the user, not to us.

### 6. Can a compromised identity be replaced without rebuilding the Space?
**Yes — this is what per-member identity buys.** Each member is a **signing key** bound by a grant, not the room
itself. To replace a compromised member: **revoke** their grant (shipped), **admit a new key** for them (a fresh
grant / `AgentEntry`), and **re-key the epoch** (designed) so the old key reads nothing further. The Space, its
history, and every other member are untouched. Same for an **agent** — its identity is its key, so a rotated key is
a one-line allow-list change, not a migration.

### 7. What metadata remains visible to the platform?
Honestly: **timing, sizes, and coarse structure — never content or membership.** The platform stores the
`mk`-commitment, the **sealed** config (opaque), and the **sealed** ledger (opaque), and it observes *when* turns
and polls happen and *how big* the ciphertext is. It does **not** see the conversation, the members' names (sealed
in the config), or — in invite mode — any real-world identity (only public keys). In **Google-sign-in** mode it
sees the presenter's email **transiently, at verify time, and discards it** (never stored). The irreducible leak is
**timing correlation** — A posts, B polls moments later, repeatedly — which no content encryption removes; only
transport-level mixing (OHTTP/relay) blunts it, and even that leaves rhythm. This is the same honest limit push
notifications carry.

---

## 8. The lifecycle status, precisely

| Capability | Status |
|---|---|
| Remove a member — cut **writes** (revoke) | **shipped** (gated Spaces) |
| Per-member identity, independent + expiring, individually rotatable | **shipped** |
| No operator recovery key (no backdoor) | **shipped** — and now enforced on every path |
| Remove a member — cut **reads** (epoch re-key, forward secrecy) | **shipped in the Bridge**; **designed** for the single-Space ledger |
| Scoped, forward-only reads for an agent (seal per key, from admission) | **shipped** (`view` / `fetchview`) |
| Rotate a compromised member/agent key without rebuilding the Space | **shipped** (identity + revoke) + **designed** (re-key for full read-cut) |
| Device-loss recovery (user-held: recovery code / k-of-n social) | **designed** — roadmap, never operator-held |
| The Companion as the key home + recovery + notifications | **designed** — roadmap (§9) |

---

## 9. The Witbitz Companion — keys leave the URL

The deepest fix for bearer-link lifecycle problems is to stop treating a **URL** as the key vault. The **Witbitz
Companion** — a single native app, installed once — is the device-side runtime that carries the *un-static*
capabilities for every Witbitz app: a **real key home** (device keystore, not `localStorage` or a copied link),
**local decrypt** of peer content, **user-side rotation & recovery** (receive re-keyed epochs without re-sharing a
link; hold your own recovery — a code or k-of-n social recovery, never an operator key), and **install-once
notifications**. Keep every app a pure certifiable static page; put the one thing that must persist — keys,
recovery, reach — in a single runtime the user controls and we certify.

**Roadmap, not shipped**, and honest about scope: it closes the **peer** half only (agent turns still run
server-side until the attested tier), and it consolidates rather than removes the device↔room reach-me linkage;
interim = content-free Web Push. **Full treatment: [The Companion](https://docs.witbitz.chat/docs/the-companion.md).**

---

## 10. Code map

| Concern | Where |
|---|---|
| Per-member identity + revoke | `agent/spaceEntrySig.mjs`, `agent/spaceAgentKeys.mjs`, admission in `agent/spaceService.mjs` |
| Epoch re-key + forward secrecy (the Bridge) | `agent/bridgeMembership.mjs` (`openSpace`/`admit`/`revoke` epochs) |
| Scoped, forward-only agent reads | `agent/spaceScopedView.mjs` (`view` / `fetchview`) |
| Key model + k-of-n (the recovery primitive) | `spaces/public/spaceConfig.js`, `spaces/public/shamir.js`, `spaces/public/invite.js` |
| Seal / no-operator-key | `agent/envelope.mjs` (`seal`/`open`, `sealTo`/`openBox`) |
| The Companion (design) | `docs/witbitz-companion.md` |
