OverviewFilesCommitsIssuesDocsReleasesPeers

favela-identity commits / 2e09557

spec/identity 6.1.3-6.1.4: per-device rotation keys, and a device is not an atproto node
Corrects the residual I wrote an hour ago. PLC takes a LIST of rotation keys and hpp already ships 'rotation add'; #47 measured wj62 at exactly one, never rotated - a usage gap, not a capability gap, and per-device rotation keys are #49's own title. Separate the capabilities: ONE signing key (replaceable, held by the bridge), N rotation keys (durable, one per device, never shared). Lose all but one device and it still operates. A device can ROTATE without ever SIGNING, which is what makes the single signer safe. Consequence: a device is a room participant, not an atproto node - #36 stops being a requirement. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2e09557e41ef609e180ccec609482f889330174d
by plankatron <fleeky@gmail.com> · 2026-09-06T00:09:43.000Z

Changed files (1) +41 -4

spec/identity.md +41 -4
……@@ -205,10 +205,47 @@ among N devices that *could* sign. With one signer there is nothing to elect.
205205projection stalls, while the canonical record still replicates to every device. **A peripheral being
206206down degrades the peripheral** — which is the whole claim of `SOCIAL-MODEL.md`.
207207
208⛔ **The residual, and it is not solved: the PLC rotation key.** If the bridge box dies the DID
209signing key dies with it, PLC is append-only so the DID survives *frozen*, and recovery is **only**
210via the rotation key — a different secret with different backup requirements. That is hyper-social
211#48's scar (rotation authority recovered from a backup) and #49. **Nothing here addresses it.**
208#### 6.1.3 Survivability — per-device ROTATION keys, which PLC already gives us
209
210⚠ **Corrects the paragraph that stood here.** It said the PLC rotation key was an unsolved residual:
211if the bridge box dies the signing key dies with it, and recovery is a procedure. That is only true
212because we have **one** rotation key.
213
214**PLC takes a LIST**, and hpp already ships the tooling (`rotation-cli.js:114` reads
215`head.rotationKeys || []`; `rotation add --did D --key K` *"register K as an additional rotation
216key"*; `rotation gen` mints an offline one). hyper-social #47 measured wj62: **exactly one rotation
217key, never rotated** — the fragility is a *usage* gap, not a capability gap. And per-device rotation
218keys are literally #49's title.
219
220**Separate the two capabilities:**
221
222| | holders | durability |
223|---|---|---|
224| the **signing** key | **one** — the bridge (§6.1.2) | **replaceable** |
225| **rotation** keys | **one per device**, all registered in the DID doc | **durable, never shared** |
226
227⇒ **Lose every device but one and that one still operates**: its rotation key mints a new signing key
228and installs it on a new bridge. Survivability becomes a **property**, not a recovery procedure. And
229revoking a device is a rotation op removing its key — the thing a shared signing key can never offer.
230
231⇒ **A device can ROTATE without ever SIGNING**, which is what makes §6.1.2's single signer safe.
232
233#### 6.1.4 A device is a room participant, not an atproto node
234
235What a phone actually needs collapses:
236
237| needs | does **not** need |
238|---|---|
239| corestore, autobase, hyperswarm | `atproto-repo` — MST/CAR/commit |
240| the record store (overlay) | `repo-manager`, the signer, the firehose |
241| `favela-markdown` | PLC submit, sessions, the membrane |
242| device key + attestation + **rotation key** | **the DID signing key** |
243
244⇒ hyper-social **#36 ("favela as a FULL NODE on Android") stops being a requirement**, and #39's
245527 MB→117 MB fight was largely about carrying a stack a room participant does not need.
246
247⚠ **Genuinely still open:** an *offline* recovery key for the case where every device is lost at once
248(`rotation gen` exists for exactly this), and where it is kept. That is the surviving part of #49.
212249
213250⚠ **Second, smaller:** a co-owned community room has N co-owners but one `bridge:bsky`, so *who runs
214251the community's bridge* becomes a governance question. Coherent — ap-bridge is already single-instance