fix(relay): republish group metadata when a huddle auto-archives - #4918
Open
Pratikkale26 wants to merge 1 commit into
Open
fix(relay): republish group metadata when a huddle auto-archives#4918Pratikkale26 wants to merge 1 commit into
Pratikkale26 wants to merge 1 commit into
Conversation
When the last audio peer leaves, the relay archives the huddle's ephemeral
backing channel but never republishes kind:39000. Clients build their
channel list from kind:39000, so the database and the event projection
diverge permanently: the relay knows the channel is archived, while every
client — including a fresh install on a new machine — keeps showing the
huddle channel indefinitely.
Nothing repairs it afterwards. The ephemeral reaper is the one path that
would republish, but `reap_expired_ephemeral_channels` filters
`archived_at IS NULL`, so a row archived here is never picked up. And
kind:39000 is replaceable, so the stale event is what every future client
syncs. The channel also cannot be removed by any client action: archiving
it is refused by the archived-channel guard.
The two other archive paths already converge — the owner-driven kind:9002
handler and the reaper both call `emit_group_discovery_events`. Only the
audio auto-end path skipped it, emitting kind:48103 alone.
Mirror the reaper after a successful archive:
- `emit_group_discovery_events` republishes kind:39000, which stamps
`["archived", "true"]` from `channel.archived_at`. This is the fix.
- `evict_all_channel_subscriptions` drops live subscriptions so connected
clients remove the channel immediately rather than on next reconnect.
Both are best-effort and logged on failure: a discovery hiccup must not
change huddle teardown, which has already completed at this point.
The reaper's `channel_auto_archived` system message is deliberately not
mirrored — this path already emits kind:48103 (huddle ended), which is the
precise signal for a huddle, so a second notice would be redundant.
Adds an e2e test that drives the real path: create the parent and
ephemeral channels, publish the kind:48100 link, connect a peer to
`/huddle/{id}/audio`, complete the NIP-42 handshake, wait for `joined`,
drop the socket, then assert the newest kind:39000 carries
`["archived", "true"]`. It fails against the unfixed relay
(`left: Some(false)`) and passes with the fix.
Fixes block#4879
Signed-off-by: pratikkale26 <pratikkale7661@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When the last audio peer leaves a huddle, the relay archives the ephemeral backing channel in the database but never republishes kind:39000. Clients build their channel list from kind:39000, so the channel stays in the sidebar forever, on every client, including a fresh install — and no user action can remove it.
Fixes #4879.
The divergence, measured
Against a local relay on
main, after the last audio peer drops:The relay knows. No client ever will.
Root cause
crates/buzz-relay/src/audio/handler.rs— the auto-end path archives the channel and emits only kind:48103:Every other archive path publishes the discovery update:
handlers/side_effects.rs:1649)main.rs:685)audio/handler.rs)This does not self-heal. The reaper is the one path that would republish, but
reap_expired_ephemeral_channelsfiltersarchived_at IS NULL, so a row archived here is never picked up. And kind:39000 is replaceable, so the stale event is what every future client syncs.The fix
After a successful
archive_channel, mirror what the reaper already does:emit_group_discovery_events— republishes kind:39000, which stamps["archived","true"]fromchannel.archived_at. This is the actual fix.evict_all_channel_subscriptions— drops live subscriptions so connected clients remove the channel immediately, rather than waiting for a reconnect.Both are best-effort and logged on failure: a discovery hiccup must not change huddle teardown, which has already completed by this point.
One deliberate omission
The reaper also emits a
channel_auto_archivedsystem message. I left that out here: this path already emits kind:48103 (huddle ended), which is the semantically precise signal for a huddle, so a second "auto archived" notice would be redundant in the timeline. Happy to add it if maintainers prefer strict parity with the reaper — it's a one-line change.On the broader suggestion in the issue
The issue notes that coupling the republish to the archive itself would make this class of divergence unrepresentable. I agree that's the better end state, but
db.archive_channellives inbuzz-db, which has no access to relay state and cannot emit events, so it would need a relay-level wrapper adopted by all three paths. That's a refactor of two currently-working paths and felt out of scope for a bug fix — happy to follow up with it separately if wanted.Testing
New
crates/buzz-test-client/tests/e2e_huddle_archive.rsdrives the real path end to end: create parent + ephemeral channel, publish the kind:48100 link, connect a peer to/huddle/{id}/audio, complete the NIP-42 handshake, wait forjoined, then drop the socket and assert the newest kind:39000 carries["archived","true"].Validated by reverting the fix and re-running — it fails with:
Related