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
{{ message }}
Repository navigation
Commit 5182a1f
Browse filesBrowse the repository at this point in the historyBrowse files
fix(cloud): three more review findings from #92 — late answers, a deadline, in-place resets
1. A refresh's answer could be applied to a session it was not about. The request
is out for as long as the network takes, and nothing tied its result to the
session it started against. A 401 arriving after the user had signed in again
deleted the pair that sign-in had just stored and marked it expired. A 200
arriving after a sign-out signed them back in; after a sign-in as someone else
it filed the old account's tokens under the new name.
Two checks now, because there are two ways for the session to change. A
generation counter — bumped by sign-in, sign-out and expiry — covers this
window exactly. Comparing the stored refresh token with the one that was sent
covers another window, which no counter here can see. And every credential
change runs through one queue (withSessionLock), because each is several awaits
long: without it a sign-in can land between an expiry's "is this still the dead
session?" and its deletes — the reviewer's point that comparing tokens is not
enough on its own. The queue is per process; between windows the comparison
narrows that gap to milliseconds, it does not close it.
A superseded answer changes nothing and reports whether a token is in place to
retry with. If there is none and this window still believes it is signed in,
another window ended the session first, and this one catches up: the card, and
a popover and footer that stop claiming it is live.
2. The refresh had no deadline, and `ready` waits on it before it restores the
chat. A host that accepted the connection and then went quiet held the
transcript, the config and the review controls behind it. The whole exchange
now gets ten seconds: the timer is cleared after the body is read, not at the
headers. Running out is "this attempt failed", so the tokens stay.
3. The replay ran only on `ready`, and I was wrong about what sends one. New Chat
and a session resumed from History do not reload the document: they post
`reset`, which empties the log in place, card included. The previous commit's
comment and message said otherwise. A checkpoint restore does the same by
dropping every node after the restored turn. All three now replay an unanswered
expiry afterwards — under the restored transcript when resuming.
Verified: 43 suites, 741 cases, 0 failing. sessionExpiredHost.test.js goes from 25
to 44 cases, and its stand-in stores now answer a turn of the event loop later, as
the real ones do: that gap is where two changes interleave, and a stand-in that
answered at once would have hidden what the lock is for. Each defect put back fails
its own case: every answer applied -> "the new access token survived"; no token
comparison -> another window's sign-in; no counter -> a sign-in that brought no
refresh token of its own; no lock -> the sign-in started mid-expiry, with the
interleaved writes in the message; no signal -> the silent host never finishes;
timer cleared at the headers -> the stalled body; timer never cleared -> aborted
after the fact; each replay removed, or run before the transcript -> its own case.
tsc --checkJs reports nothing new. In headless Chrome against the real chat.html,
`reset`, a resume and a checkpoint restore each remove the card, and the replay
puts it back at the bottom.
0 commit comments