fix(server): release settled voice recovery intent during drain

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-25 09:40:41 -05:00
1 parent 1bf70185d2
commit 1b43332c74
3 files changed
+47 -2

No files matched your search

@@ -0,0 +1,34 @@
# Voice recovery drain repair
Owner: slice 21, PR #17576. Reviewed baseline: 1bf70185d2.
Greptile finding 4370544173 is valid. The worker retained dirty scopes while
paused, and reported those in-memory hints as pending work. After the producer
committed, the coordinator therefore retained its intent activity hold. No SQL
was required to reproduce the blocked drain; the earlier quiet assertion checked
SQL only and missed the nonzero idle counter.
The worker now reports pending dirty scopes only while dispatch is permitted.
It still retains every hint and next deadline. The coordinator independently
checks databaseWorkPending, so an open/uncertain transaction retains its activity
hold until transaction reconciliation establishes settlement. Paused timers then
use the existing passive-maintenance path without changing the idle generation.
Resume processes the retained first session without another producer signal.
No provider behavior or external sleep eligibility rule changes.
The strengthened real-PostgreSQL test proves: an open write during drain retains
an activity hold; commit releases it; a further minute causes neither SQL nor
an idle-snapshot change; resume processes the one retained session exactly once.
- /tmp/sleep21-drain-before.log: original worker fails, active is 1 instead of 0.
- /tmp/sleep21-drain-tests.log: all 11 voice recovery lifecycle tests pass.
- /tmp/sleep21-drain-typecheck.log: production server typecheck passes.
- Dedicated migrated database: paperclip_sleep21_drain_20261025_test.
Propagate this predicate into slice 22's extracted scoped-deadline worker and
all descendants, then rerun its existing consumers. The earlier tool-health,
Discord command, and receiver workers have the same predicate pattern; audit
and repair those at their own parent PRs as a separate propagation pass. Do not
report all stack drain behavior fixed from the voice test alone. The company
inbound cleanup/deletion policy, older E2E failure, current chat milestone audit,
and full original inventory remain outstanding.
@@ -90,7 +90,16 @@ const support = external ? { supported: true } : await getEmbeddedPostgresTestSu
await settled(); expect(inspect).toHaveBeenCalledOnce(); await quiet();
});
it("preserves the first session during drain without passive database reads", async () => {
await start(); await settled(); enabled = false; await session(); await quiet(60_000); expect(inspect).not.toHaveBeenCalled();
await start(); await settled(); enabled = false;
await db.transaction(async tx => {
await session({}, tx as unknown as typeof db);
await vi.advanceTimersByTimeAsync(60_000);
expect(idleWorkSnapshot().active).toBeGreaterThan(0);
expect(inspect).not.toHaveBeenCalled();
});
await vi.waitFor(async () => { await vi.advanceTimersByTimeAsync(1000); expect(idleWorkSnapshot().active).toBe(0); });
const drained = idleWorkSnapshot();
await quiet(60_000); expect(idleWorkSnapshot()).toEqual(drained); expect(inspect).not.toHaveBeenCalled();
enabled = true; await settled(); expect(inspect).toHaveBeenCalledOnce(); await quiet();
});
it("retries unavailable authority without ending a valid provider call", async () => {
@@ -78,7 +78,9 @@ export function registerVoiceRecoveryWork(
}
if (errors.length) throw new AggregateError(errors, "Voice session recovery could not settle");
},
hasPending: async () => dirty.size > 0,
// Retain scopes/deadlines for resume without retaining a settled write's
// idle hold during drain. The coordinator still fences unresolved XIDs.
hasPending: async () => canRun() && dirty.size > 0,
nextRunAt: next,
});
return worker;