mirror of
https://github.com/stablyai/orca.git
synced 2026-09-23 16:02:24 +00:00
* fix(browser): serialize cookie imports per partition (STA-4601) Two concurrent cookie imports on one partition can erase a session. Nothing serialises imports per partition — neither the renderer IPC handler (browser-session-profile-ipc.ts) nor the runtime RPC method (orca-runtime-browser.ts) — and the clear lock covered only the clear itself, so it was released before the writes and before any rollback. Reachable interleaving: import A replaces cookies for its imported domains, releases the lock, and later fails a write; import B clears and writes; A's rollback then removes cookies B already wrote and reported as imported. Path B has the same shape: A clears, B clears, then A writes its cookies on top of B's jar. Fix: one lock spans the whole live-jar transaction on both paths — the clear/replace, the writes, and the rollback. withCookieClearLock becomes acquireCookieMutationLock/withCookieMutationLock so path A can hold it across a try/finally rather than a single callback. Rebased onto #15030 (STA-4300), which rewrote this file: imports now write through CDP identities, so path A's writes moved from an inline cookies.set() loop into writeImportedCookies(), path B's into the same helper, and — the part that matters for a lock — importValidatedCookies no longer holds the Electron Session at all. It receives a CookieImportTarget that hides the Session behind openWriteStore(), and openWriteStore() builds a FRESH adapter per call, so keying the lock on anything reachable from it would serialise nothing. The target therefore carries mutationLockOwner, set to session.fromPartition's instance, which is the same object the native path locks on. That is what keeps both paths on one key per partition. Deliberately bounded: this covers the LIVE JAR only. Staging and cold-start replay keep their existing semantics, so two other pre-existing hazards in that subsystem are untouched and still open — the crash window between the clear and the result, and a permanently-armed replay when replay keeps failing. Both need the pending-image operations to become provable, which is a different change. The lock is keyed per owner, so imports into different partitions still run concurrently. Mutation-proved against the rebased tree, every mutation structure-preserving (brace/paren balance pinned) and every one re-run rather than carried over: dropping path A's acquire reddens the file-import detector; keying path A's acquire on a fresh object instead of mutationLockOwner reddens it too — the lock-present-but-miskeyed shape this rebase risks; replacing path B's lock with a passthrough reddens the native detector; doing both reddens both, which rules out incidental serialisation; and neutering the cold-init probe's lock reddens the new probe detector. That last detector is new: neutering the probe lock previously left all 779 browser tests green, so the probe's protection was unproven. The concurrency suite's store stub also gained writeCookieIdentity and getStoragePath. Without them the STA-4300 code throws a TypeError that writeImportedCookies catches as a write rejection, so the imports would have taken the failure path while the ordering assertions still passed. Each real import test now asserts writeCookieIdentity was CALLED, and that cookies.set never was. src/main/browser: 72 files, 780 tests, green; typecheck, oxlint, type-aware code quality, oxfmt and the max-lines ratchet all clean. * fix(browser): serialize native cookie staging * test(browser): pin native flush serialization * test(browser): pin staged cookie replay ordering * test(browser): remove vacuous staged replay detector * test(browser): detect stale native staging images * test(browser): guard cookie import ordering events * test(browser): cover staging lock boundary