Startup self-prune of stale bridge/ghost devices (device hygiene automation) #53
Labels
No labels
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
dark/nether-voicebridge#53
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Motivation (root-caused 2026-07-03)
Encrypted Matrix→Discord went silent on all bridges: the manual stale-device purge (
tuwunel-cleanup.txt, 138!admin users delete-devicecommands) included the bridges' LIVE bot devices (dark-voice-v3wsney6,light-voice-y5qnpmvj,light-gaming-gh4bf4g2).Chain of failure:
MissingKeyforever → Matrix speakers inaudible on Discord. No errors anywhere on the bridge, client, or homeserver.Fix applied (operational): delete the store's
device_idmarker →resolve_store_device_idmints a fresh unique id + resets the bot crypto store → clients see a genuinely new device and key it within ~1s. Verified live on all three bridges.Proposed hardening
Automate device hygiene so manual cleanup lists are never needed again:
GET /_matrix/client/v3/devices), delete any device matching this bridge's<bridge-slug>-prefix that is not the current minted id.as_tokenmasquerade — delete staleD<discord-id>-*devices that don't match the current per-store salt-derived id.Rules for any remaining MANUAL cleanup (until this ships)
device_idmarker (<data_dir>/<bridge>/device_id).D<discord-id>-<current-salt>, salt in<bridge>/ghost_device_salt).tuwunel-orphan-devices-20260703.txt.Notes
Implemented and shipped in v0.3.0-alpha.3 (master
436a5af; feature commitse22ca71+2bc1a8c).Two mechanisms, both live-verified end-to-end on the production deployment (2026-07-04):
Deletion self-heal — before reusing a persisted identity (bot via
resolve_store_device_id, ghost via its pickled identity blob), the bridge checks/keys/query; if the device keys were deleted server-side while offline it re-provisions a fresh device instead of resurrecting the old id. Verified by deleting the live Dark Voice bot device in the admin room with the bridge stopped: restart detected it, re-keyed, the listener's client keyed the new device in ~1 s, audio confirmed both directions. Fails open on transient errors.History-scoped pruning — every re-mint records the abandoned id (bot:
<store>/retired_device_ids; ghost:retiredfield in the identity blob); startup deletes exactly those ids. A store can only delete ids it itself retired, so parallel deployments (dev box + VPS on one appservice) can never prune each other's live devices — the failure mode that motivated this issue is structurally impossible. Config:prune_stale_devices(default on).Tuwunel caveat (live-probed): no client-API device deletion exists for appservice users today — masqueraded DELETE is 403, and even a self-delete by the device's own session gets a 401 with empty UIA flows (no MSC4190). Pruning therefore soft-fails there with one WARN and retains the history; it flushes automatically if/when the homeserver allows deletion. Until then, stale-device removal remains an admin-room operation.
Operator leftover from testing:
!admin users delete-device @voicebridge_as:nether.im dark-voice-prunetest0