feat(gateway): add cooperative host suspension#103618
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed July 10, 2026, 3:19 PM ET / 19:19 UTC. Summary Reproducibility: not applicable. This PR introduces a new lifecycle capability rather than reproducing an established current-main bug. Review metrics: 3 noteworthy metrics.
Stored data model Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Maintainer decision needed
Security Review detailsBest possible solution: Keep one canonical core admission/coordinator path, but merge only after redacted exact-head live transcripts prove both WebSocket and Admin HTTP flows and the Gateway owner explicitly accepts the cooperative—not total-process—quiescence contract. Do we have a high-confidence way to reproduce the issue? Not applicable: this PR introduces a new lifecycle capability rather than reproducing an established current-main bug. Is this the best way to solve the issue? Yes, provisionally: an atomic core fence is the narrowest way to prevent races that an observational plugin cannot close, and one canonical coordinator is preferable to platform-specific snapshot hooks; exact-head proof and product acceptance remain required. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against e1934d968e43. Label changesLabel changes:
Label justifications:
Evidence reviewedWhat I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
296414e to
0309c02
Compare
c18474c to
e475996
Compare
|
Maintainer proof complete for exact head Review fixes now included:
Exact proof:
Known scope boundary: this is a cooperative tracked-work fence, not third-party channel shutdown or an OS/process-tree snapshot adapter. #86876 remains open for those broader controller/plugin concerns. @clawsweeper re-review |
|
🦞👀 Command router queued. I will update this comment with the next step. |
|
Merged via squash.
|
* feat(gateway): add cooperative suspension preparation * style: satisfy suspension lint checks * test(gateway): reset work admission between shared suites * fix(gateway): reject upgrades during suspension * fix(gateway): preserve admitted work during suspension * test(gateway): isolate suspension and restart state * fix(gateway): close suspension false-ready gaps * refactor(protocol): slim suspension declaration graph * refactor(plugin-sdk): sever protocol registry edges * fix(gateway): preserve admitted restart follow-ups * fix(gateway): make suspension recovery fail closed * fix(protocol): keep validation formatter re-export only * test(gateway): simplify deferred fixture type * style(gateway): clarify suspension entry name * fix(gateway): retain detached work admission
Partially addresses #86876.
What Problem This Solves
External hosting controllers had no atomic way to verify that a Gateway had stopped accepting new tracked user work and was idle before freezing or snapshotting its process.
A read-only preflight can race with a new RPC, session turn, cron tick, HTTP request, or detached persistence/delivery task. Restart draining is one-way, so it cannot safely represent an abandoned or reversible host snapshot operation.
Why This Change Was Made
This adds a host-neutral Gateway contract instead of a platform-specific API:
gateway.suspend.preparegateway.suspend.statusgateway.suspend.resumepreparecloses process-wide root, session, and command admission; pauses automatic cron scheduling; and synchronously inspects tracked active work. It returnsreadyonly when the snapshot is idle. If work is active, it restores scheduling and admission before returningbusy.A ready lease lasts two minutes, can be renewed with the same stable
requestId, auto-resumes on expiry, and requires the matchingsuspensionIdfor explicit resume. Scheduler-resume failures remain fail-closed and retryable. Restart signaling shares the same admission state, preventing a signal from racing a ready lease or reopening work during restart drain.The generic fence lives in core. The Admin HTTP plugin exposes the same RPC methods as an alternate authenticated control path. The protocol change is additive and introduces no new config or environment variable.
This is complementary to the durable queue work in #51620 and #82572: the queue preserves accepted work, while this contract creates a bounded cooperative idle window for host snapshots.
User Impact
Host controllers can now coordinate a bounded idle window:
gateway.suspend.prepare.busyresult while leaving the process running.expiresAtMsafter areadyresult.gateway.suspend.resumeafter thaw or abandonment.While prepared, new WebSocket handshakes are rejected; existing connections can call only suspension control methods; other RPCs return retryable
UNAVAILABLE; automatic cron ticks remain paused; built-in HTTP user-work routes return503;/healthzremains live; and/readyzreports not ready. A retained authenticated WebSocket or pre-enabled Admin HTTP RPC route is required for explicit resume.This is a cooperative tracked-work fence, not general process quiescence. It does not persist incoming messages, stop third-party channel transports, fence external ingress, or prove arbitrary plugin/background work idle. The host remains responsible for fencing ingress and consistently freezing or snapshotting the full process tree and filesystem. If the control connection is lost, admission reopens when the lease expires.
Evidence
e475996d946af6810c053f14a69684a6f9ebfb46; Git tree35b61e79b5b2a8f1a535125081936ca4551afff0.run_45c5519361afbuilt that exact tree and passed the persistent WebSocket/Admin HTTP contract: baseline health/readiness, ready lease, retained status, prepared200/503probes, retryable unrelated-RPC refusal, fresh-WebSocket503, mismatch preservation, matching resume, restored readiness, and idempotent repeat resume.run_5d1bf9ff69fapassed 159 focused protocol, Gateway, coordinator, cron, admission, detached agent/chat, and followup-drain tests across six Vitest shards.patch is correct, confidence 0.88).Generated TypeBox protocol schemas, Swift client models, and the docs map are current.
vgateway.quiesceis not introduced; the public API is the host-neutralgateway.suspend.*family.