Apply store-paired device_id to per-ghost crypto clients (kill SigningKeyChanged churn) #35

Closed
opened 2026-06-19 17:01:58 +00:00 by robocub · 2 comments
Collaborator

Follow-up from the #30 fix (84b0a0c).

The per-ghost crypto clients (crates/matrix-rtc/src/rtc/ghost.rs::build_ghost_crypto_client) use a stable device_id of D<discord_user_id> — the same reuse-with-new-keys pattern that broke the bot subscriber on a fresh store in #30.

  • Impact: does not break audio (ghosts are senders — they Olm-encrypt to the humans' own stable devices), but on a fresh/changed store it produces the Rejecting device update ... SigningKeyChanged log churn at startup.
  • Fix: apply the same store-paired-device-id approach used for the bot in #30 (matrix.rs::resolve_store_device_id) to each per-ghost store dir, so ghost identities stay consistent across wipes and the churn disappears.
  • Priority: low / cleanup.
Follow-up from the #30 fix (`84b0a0c`). The per-ghost crypto clients (`crates/matrix-rtc/src/rtc/ghost.rs::build_ghost_crypto_client`) use a stable `device_id` of `D<discord_user_id>` — the **same reuse-with-new-keys pattern** that broke the bot subscriber on a fresh store in #30. - **Impact:** does **not** break audio (ghosts are senders — they Olm-encrypt to the humans' own stable devices), but on a fresh/changed store it produces the `Rejecting device update ... SigningKeyChanged` log churn at startup. - **Fix:** apply the same store-paired-device-id approach used for the bot in #30 (`matrix.rs::resolve_store_device_id`) to each per-ghost store dir, so ghost identities stay consistent across wipes and the churn disappears. - **Priority:** low / cleanup.
Author
Collaborator

Related to the wedge in #52 / #34. Minting a fresh crypto device every ghost lifecycle (post-#44 in-memory design) is a primary driver of the stale-device pile-up that wedges listener Olm sessions. Stabilizing the ghost crypto identity keeps device lists clean and lets a listener's session persist across restarts. Note the tension with #44 (storeless/in-memory = SigningKeyChanged-safe via fresh device): stabilizing needs a light account-persistence approach (pickle/restore, not a held per-ghost SQLite deadpool — that was #44's FD killer). #34 (prune-on-startup) fixes the observed silence even with churn, so this is the secondary/optimization half.

**Related to the wedge in #52 / #34.** Minting a fresh crypto device every ghost lifecycle (post-#44 in-memory design) is a primary driver of the stale-device pile-up that wedges listener Olm sessions. Stabilizing the ghost crypto identity keeps device lists clean and lets a listener's session persist across restarts. Note the tension with #44 (storeless/in-memory = `SigningKeyChanged`-safe via fresh device): stabilizing needs a *light* account-persistence approach (pickle/restore, not a held per-ghost SQLite deadpool — that was #44's FD killer). #34 (prune-on-startup) fixes the observed silence even with churn, so this is the secondary/optimization half.
Author
Collaborator

Shipped in v0.3.0-alpha.2 (master 1bf9723). Ghost crypto device ids now fold in a per-store saltD<key>-<salt> (resolve_ghost_device_salt), pairing the ghost device identity with its crypto store exactly like the bot's minted id from the #30 fix (resolve_store_device_id). A wiped/copied/second store re-provisions a brand-new device instead of presenting the old id with new Olm keys, so peers never hit SigningKeyChanged; the per-lifecycle device churn this issue describes is gone.

This also turned out to be load-bearing beyond cosmetics: stable ghost identities stop the stale-device pile-up that was poisoning listener device lists and draining OTKs (the #34/#52 wedge chain).

Live-verified in prod: across the alpha.3→alpha.7 deploys, all ghost/bot device ids report reused=true and encrypted calls re-key in seconds. Closing.

**Shipped in v0.3.0-alpha.2** (master `1bf9723`). Ghost crypto device ids now fold in a **per-store salt** → `D<key>-<salt>` (`resolve_ghost_device_salt`), pairing the ghost device identity with its crypto store exactly like the bot's minted id from the #30 fix (`resolve_store_device_id`). A wiped/copied/second store re-provisions a brand-new device instead of presenting the old id with new Olm keys, so peers never hit `SigningKeyChanged`; the per-lifecycle device churn this issue describes is gone. This also turned out to be load-bearing beyond cosmetics: stable ghost identities stop the stale-device pile-up that was poisoning listener device lists and draining OTKs (the #34/#52 wedge chain). Live-verified in prod: across the alpha.3→alpha.7 deploys, all ghost/bot device ids report `reused=true` and encrypted calls re-key in seconds. Closing.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
dark/nether-voicebridge#35
No description provided.