Skip to content

feat(sidecar): per-mailbox DO-alarm polling (SidecarDO scale-out) #596

Description

@schmug

⚠️ Blocked on PR #587 — everything this issue touches lands in that PR and is not on main yet.
Automated agents/routines: do not implement this issue while PR #587 is open. Before starting any work, run gh pr view 587 -R schmug/PhishSOC --json state -q .state and proceed only if it prints MERGED; otherwise stop silently (no comment, no branch). Remove the blocked/impl-blocked labels only after #587 merges.

Task

Scale the sidecar poll loop past the stateless-cron fan-out's ceiling by moving per-mailbox polling behind Durable Object alarms (the "SidecarDO" evolution named in the design spec). Today one Worker invocation polls every sidecar mailbox sequentially each minute; at ~dozens of busy mailboxes the tick approaches wall-clock/subrequest budgets (~26 Gmail round-trips per busy mailbox).

Motivation

The spec chose stateless cron fan-out for v1 with this exact seam reserved: pollWorkspaceMailbox(env, ctx, mailboxId, cfg) is a pure per-mailbox step designed to be re-homed without rework.

Pointers

  • workers/providers/workspace.tspollWorkspaceMailbox (the re-homeable step) and pollSidecarMailboxes (becomes an alarm-healer instead of a poller)
  • workers/durableObject/ — decide: alarm on the existing MailboxDO vs a new SidecarDO class; the design spec (docs/superpowers/specs/2026-07-06-sidecar-workspace-design.md, "Approach" section) discussed the trade-offs — a new DO class keeps provider/network concerns out of the storage DO
  • wrangler.jsonc — new DO class needs a migration tag + binding (NOTE: Workers Builds deploys prod on merge; a new binding must be provisioned correctly or the deploy step fails — see repo memory)
  • .superpowers history: the poll-lease issue (fix(sidecar): poll lease — overlapping cron ticks can double-process a mailbox #591) becomes moot inside a DO alarm (alarms serialize per object) — coordinate/close accordingly

Constraints

  • Cutover must be incremental: cron fan-out remains the default; alarm mode per mailbox or via env flag until proven
  • All poll-loop invariants preserved (cursor freeze, dedupe, cap-on-processed, backoff, audit/label rules) — the existing workspace-poll.test.ts suite must keep passing against the extracted step

Acceptance criteria

  • N sidecar mailboxes poll concurrently with per-mailbox isolation (one slow tenant doesn't delay others)
  • Alarm death is self-healing (cron heals missing alarms within one hourly cycle)
  • Existing poll-step tests pass unchanged; no regression in the cron-only mode

Out of scope

Provider changes; push transport (#589) — though alarms + push compose, land them separately.

Cross-references

PR #587 (architecture decision + seam), #31, #591 (lease — superseded inside alarms), #589

Metadata

Metadata

Assignees

No one assigned

    Labels

    blockedBlocked by a dependency or unresolved problemenhancementNew feature or requestimpl-blocked

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions