Skip to content

fix(bot): reliable /play acknowledgment and a session-scoped queue - #9

Merged
Nxssie merged 5 commits into
mainfrom
fix/queue-reset-on-leave
Oct 18, 2026
Merged

Nxssie merged 5 commits into
mainfrom
fix/queue-reset-on-leave

Conversation

@Nxssie

@Nxssie Nxssie commented Oct 18, 2026

Copy link
Copy Markdown
Owner

Summary

  • Every slash command is deferred before any awaited work, so slow database writes, yt-dlp lookups or playlist inserts no longer expire the interaction ("Unknown interaction"). Each command's public/ephemeral style is fixed at defer time in lib/ack.ts.
  • The queue is now session-scoped: every path that takes the bot out of the voice channel (idle reaper, failed reconnect, /stop, guild removal, shutdown) clears the room's pending songs and their votes. Played history stays.
  • Race guards keep the reaper from leaving while a /play or an advance is in flight, and /play reports when a song was queued but playback did not start.

Changes

File Change
packages/server/src/lib/pendingQueue.ts clearPendingQueue: deletes played = false rows and their votes in one transaction
packages/server/src/lib/ack.ts Per-command reply policy and ephemeralNotice (private answer after a public defer, without leaving the placeholder hanging)
packages/server/src/index.ts Defer-first handling, leaveVoice on every leave path, reaper race guards, stale-session cleanup before /play inserts
README.md Documents the session-scoped queue and the new /stop behavior
odd/tasks/queue-reset-on-leave.md Feature document with specs, tasks and evidence

Test plan

  • bun test: 71 pass, 0 fail (new cases in ack.test.ts and pendingQueue.test.ts)
  • bun build src/index.ts --target bun: exit 0
  • Live Discord smoke test (there is no interaction harness in this repo): /play with a URL, /stop, a dropped voice connection followed by /play, and the permission denials on /stop and /reset

Review note

The branch is about 640 changed lines. Review it as one unit; e7bee73 (interaction and leave wiring) and fb02450 (review fixes) deserve the closest look.

Nxssie and others added 5 commits October 18, 2026 16:28
The pending queue belongs to one voice session, so leaving the channel has to
delete it. clearPendingQueue removes only `played = false` rows of one room and
the votes attached to them, in one transaction, and leaves played history and
other rooms untouched. Tested against the real migrations.
Discord expires an unanswered interaction after three seconds, so a command
cannot wait for database or yt-dlp work before acknowledging. The policy maps
every registered command to its ephemeral/public reply, and the test fails if a
command is ever added without one.
/play could answer after Discord's three-second window — the approval lookup
and the rememberUser upsert ran before deferReply, and either can wait on
SQLite's busy timeout — and the late reply failed with 10062 'Unknown
interaction', losing the command. Every slash command is now deferred before
the first await and every slash branch answers through editReply.

Leaving voice now also ends the queue: leaveVoice tears the guild down and
deletes the room's pending songs and their votes, on the automatic reap, a
failed reconnect, /stop, guild removal and shutdown. /stop reports the count.

The reaper skips a guild while a play request or advance is in flight, a
destroyed/disconnected connection is replaced instead of reused, a stale
Disconnected handler cannot tear down a newer connection, and /play says when
the track was queued but playback did not start.
README states that leaving the channel clears the room's pending songs and
votes, that /stop does the same, and that /reset only revives history inside
the current session. The ODD record keeps the specs, the checks and the one
piece of proof that is missing: the independent verification run failed without
a report.
@Nxssie
Nxssie merged commit 44b060b into main Oct 18, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant