Merge branch 'codex/sleep-21-voice-session-recovery' into codex/sleep-22-voice-reply-delivery

* codex/sleep-21-voice-session-recovery:
  test(server): wait for Discord recovery settlement before quiet checks
This commit is contained in:
Dotta committed 2026-10-25 05:36:29 -05:00
commit 849917b7b6
2 files changed
+20 -1

No files matched your search

@@ -185,3 +185,16 @@ always restores spies. Verification: 87 worker/coordinator/health, eight produce
and affected Slack, 57 existing lifecycle/startup tests; server types/build pass.
The health security parent is inherited through company cleanup. See the owning
Discord document for failure evidence and exact scope. Fresh remote gates remain.
## Idle assertion settlement repair
A descendant CI run (#17583, run 40184498387, server shard 11/12) observed one
scoped candidate SELECT during the rollback test's quiet interval. The test only
waited for nextWakeAt to become null. The coordinator consumes a timer before
its asynchronous transaction reconciliation and scoped load run, so null alone
can mean work is running, not settled. The test now waits for zero tracked active
work as well as no deadline before measuring the same 60-second zero-SQL interval.
No production timeout, dispatch, or quiet predicate was relaxed. All 41 real
PostgreSQL command ownership cases pass with the repair. Log:
`/tmp/sleep19-settlement-tests.log`. Propagate this owner-level change through the
stack; remote checks must verify the new heads.
@@ -1,4 +1,5 @@
import { reconcileDatabaseWork } from "@paperclipai/db";
import { idleWorkSnapshot } from "./task-admission.js";
import { DELIVERY_QUEUES, notifyDeliveryWork } from "./delivery-work-notifications.js";
import { discordCommandSchedule } from "./chat-channels/discord/command-schedule.js";
import { registerDiscordCommandWork } from "./chat-channels/discord/command-work.js";
@@ -755,7 +756,12 @@ suite("Discord command ownership store (real PostgreSQL, no network)", () => {
throw new Error("abort");
})).rejects.toThrow("abort");
await vi.advanceTimersByTimeAsync(60_000);
await vi.waitFor(() => expect(coordinator!.nextWakeAt()).toBeNull());
// A running sweep has already consumed its timer. Wait for its SQL and
// transaction reconciliation to settle before measuring idle traffic.
await vi.waitFor(() => {
expect(idleWorkSnapshot().active).toBe(0);
expect(coordinator!.nextWakeAt()).toBeNull();
});
await sqlQuiet(60_000);
draining = true;
await db.transaction(async tx => activate(tx as unknown as typeof db));