You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
test(gateway): prove drain lifecycle, WORKER_UNREACHABLE paths, and reconnect rebuild end to end (#119)
#118 already built the machinery this issue asks for: routing.ts drops a
drained/disconnected worker at admission, #forwardToWorker/#classifyRelayedError
map kind:"transport" to WORKER_UNREACHABLE, FleetLeaseIndex#rebuildFromWorker
reconciles a worker's leases on every view change, and dispatcher.test.ts
already pins §27a's ownership round-trip on a rebuilt lease. No production
code needed to change for this PR -- what was missing was the tested proof
that those pieces hold together under the specific failure shapes ADR 0005
§9/§28/§29/§30 describe, with call-count assertions rather than
where-the-grant-landed assertions.
Adds to src/gateway/fleet-coordinator.test.ts:
- a drained worker keeps its existing lease and its own client's call count
never grows, while a sibling with strictly less free capacity serves the
next request (proving drain, not capacity, excluded it)
- the same shape for a disconnected worker
- device.exec on a directory-unreachable worker answers WORKER_UNREACHABLE
without ever reaching the worker's client
- a lease.request whose uplink drops mid-call surfaces WORKER_UNREACHABLE to
the client, and once the worker's view later reports the lease it actually
granted, a retry from the same requester is refused
REQUESTER_ALREADY_LEASED rather than double-granted
Adds to src/daemon/gateway-fleet.e2e.test.ts: the flagship two-worker,
real-WebSocket scenario -- lease through the gateway, drain one worker,
kill it, restart the gateway (reusing its own directory and Filesystem so
instance.json/tokens.json/workers.json survive, exactly as a real restart
would), and prove the surviving worker's lease renews for its original
requester and is refused for anyone else post-restart.
Every new test was verified by deleting the production code it covers and
confirming the test fails first (routing.ts's drained/connected checks, the
exec reachability precheck, request()'s one-lease admission check, and --
for the e2e -- swapping in a fresh Filesystem on restart to break identity
continuity), then restored.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MA98m7ua7qvDFZjxFaww6Z
* #119's own flagship: drain semantics, `WORKER_UNREACHABLE`-shaped exclusion, and reconnect
230
+
* rebuild, proved together over real processes and a real WebSocket restart -- not the
231
+
* scripted uplink `fleet-coordinator.test.ts` and `dispatcher.test.ts` already cover each
232
+
* piece of in isolation (including §27a's ownership round trip, pinned there too). What only
233
+
* this shape of test can catch: the gateway's own persisted state (`instance.json`,
234
+
* `tokens.json`, `workers.json`) actually surviving a real `stop()`/`startDaemon()` cycle, and
235
+
* a real worker's own `GatewayUplink` actually redialling and reconnecting on its own backoff
236
+
* once the new process is listening again.
237
+
*/
238
+
it("drains one worker, kills it, restarts the gateway, and proves the surviving worker's lease outlives the restart with renewing resumed (ADR §9/§27a/§30, #119)",async()=>{
0 commit comments