fix(server): sweep dead dev session cookies at pairing - #47
Merged
Merged
Conversation
Every loopback dev server minted a unique 30-day session cookie on localhost and nothing ever removed one, so a few dozen paired worktrees pushed request headers past Node's 16KB limit and Vite answered 431 for every dev server on the machine. Dev cookie names now encode the state directory instead of a hash. When a dev server pairs a browser, it expires sibling dev cookies whose state directory no longer exists on disk, plus legacy-hash cookies on its own port. Live parallel worktrees are untouched; hosted and desktop cookie names are unchanged. Built by GPT-5.6 Sol via Codex CLI from a Claude Fable 5 spec; reviewed and verified by Claude Fable 5 in Claude Code.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Every loopback dev server mints a unique session cookie (
t3_session_<port>_<hash>) so parallel worktrees onlocalhostdo not clobber each other. They live 30 days, are httpOnly, and nothing ever removes one. Cookies are host-scoped, not port-scoped, so every paired worktree leaves a ~600 byte cookie behind after it is pruned. Around 25-30 of them push the request header past Node's 16 KB default and Vite answers431 Request Header Fields Too Largefor every dev server on the machine.Fix
t3_session_<port>_<base64url(stateDir)>) instead of a one-way hash, so any dev server can tell which directory a sibling cookie belongs to.Max-Age=0) every sibling dev cookie whose state directory no longer exists on disk, plus legacy-hash cookies on its own port. Deterministic: no TTL change, no port probing. Live parallel worktrees, custom--home-dirservers, and stopped-but-present worktrees keep their sessions.t3_session) and desktop (t3_session_<port>) names are unchanged. No client parses the name format.auth/utils.ts;auth/http.tsonly gathersFileSystem.existsresults and merges the expiry cookies. Only runs whendevUrlis set.docs/internals/environment-auth.md.Accepted trade-off (documented in code): a page on another localhost origin could craft cookie names and observe expiry as a local path-existence oracle. Dev servers only; that page already runs on the same machine.
Verification
vp test run apps/server/src/auth/utils.test.ts— 9 passed (naming, decoding, sweep planner).vp test run apps/server/src/server.test.ts -t "sweeps stale development session cookies when pairing"— passes (own cookie set, stale + legacy same-port expired, live sibling untouched).reports thread HTTP and WebSocket transfer budgetsinserver.test.tsfails identically on unchangedorigin/mainin this environment; unrelated.Not visible in the web app. To observe: pair a fresh worktree after this ships and inspect the pairing response's
Set-Cookieheaders in devtools. Legacy hashed cookies already in the jar are only swept when a new server lands on their port; clearinglocalhostcookies once after merge is the fast path.Built by GPT-5.6 Sol via Codex CLI from a Claude Fable 5 spec; reviewed and verified by Claude Fable 5 in Claude Code.