scheduled.ts
@file The escalation sweep: "asleep candidates get pinged on a follow-up…
Overview
@file The escalation sweep: "asleep candidates get pinged on a follow-up
if nobody accepts within a configurable window." Runs off a Cron Trigger
(wrangler.toml [triggers]) rather than any in-request timer, since a
Worker has no way to schedule work minutes after a request has already
finished — this is the one part of the bot that is not driven by a
Discord interaction at all.
depends on discordRest.ts oauthLinks.ts oauthState.ts testRequestContainer.ts testRequests.ts · used by index.ts
API
Fexport async function runEscalationSweep(db: D1Database | undefined, botToken: string | undefined, correlationId: string, now: number, escalateMinutes: number): Promise<SweepResult>
One sweep tick. Every step degrades independently: a request whose candidate lookup or escalation-mark fails is skipped (logged) rather than aborting the whole sweep, so one bad row cannot block every other pending request's escalation.
scheduled · calls asleepUnpingedCandidates, buildEscalationPing, markEscalated, pendingUnescalated, postMessageFexport async function runAbandonedLinkPurge(db: D1Database | undefined, correlationId: string, now: number): Promise<number>
Delete OAuth rows stranded between the two legs. Separate from the escalation sweep and not folded into it, because the two have different dependencies: escalation needs a bot token and does nothing without one, while this needs only D1. A deployment that never set DISCORD_BOT_TOKEN must still not accumulate live credentials. The cutoff is the OAuth state TTL. Past it the state row is refused at read time, so the flow that would have scrubbed these tokens can no longer be completed by anyone — the row is unreachable, not merely slow.
scheduled · calls purgeAbandonedLinksUndocumented (1)
escalateMinutesFrom