Repository navigation
Start Practice when session storage is blocked - #603
Merged
Merged
Conversation
sidney-Hung
force-pushed
the
lobby-blocked-storage
branch
from
November 6, 2026 13:32
e23d9fd to
8a49e07
Compare
sidney-Hung
force-pushed
the
lobby-blocked-storage
branch
from
November 6, 2026 14:31
8a49e07 to
7bdf6a2
Compare
jserv
reviewed
Nov 6, 2026
sidney-Hung
force-pushed
the
lobby-blocked-storage
branch
from
November 6, 2026 18:12
7bdf6a2 to
970da60
Compare
jserv
reviewed
Nov 6, 2026
sidney-Hung
force-pushed
the
lobby-blocked-storage
branch
from
November 7, 2026 04:52
970da60 to
fad6f07
Compare
jserv
reviewed
Nov 7, 2026
jserv
reviewed
Nov 7, 2026
sidney-Hung
force-pushed
the
lobby-blocked-storage
branch
from
November 7, 2026 05:51
fad6f07 to
3d27e68
Compare
sidney-Hung
force-pushed
the
lobby-blocked-storage
branch
from
November 7, 2026 06:08
3d27e68 to
58ec809
Compare
Contributor
|
The
Each refusal and its fix: https://github.com/sysprog21/codetrial/blob/main/docs/large-change-explanation.md#troubleshooting |
sidney-Hung
force-pushed
the
lobby-blocked-storage
branch
from
November 7, 2026 09:10
58ec809 to
3c991fc
Compare
jserv
reviewed
Nov 7, 2026
sidney-Hung
force-pushed
the
lobby-blocked-storage
branch
from
November 7, 2026 09:29
3c991fc to
e6dafc1
Compare
jserv
reviewed
Nov 7, 2026
jserv
reviewed
Nov 7, 2026
jserv
reviewed
Nov 7, 2026
jserv
reviewed
Nov 7, 2026
jserv
reviewed
Nov 7, 2026
sidney-Hung
force-pushed
the
lobby-blocked-storage
branch
from
November 7, 2026 10:52
e6dafc1 to
0f7281b
Compare
jserv
reviewed
Nov 7, 2026
jserv
reviewed
Nov 7, 2026
sidney-Hung
force-pushed
the
lobby-blocked-storage
branch
from
November 7, 2026 15:23
0f7281b to
c72a284
Compare
jserv
reviewed
Nov 7, 2026
sidney-Hung
force-pushed
the
lobby-blocked-storage
branch
from
November 7, 2026 23:48
c72a284 to
d6acc77
Compare
jserv
reviewed
Nov 8, 2026
jserv
reviewed
Nov 8, 2026
jserv
reviewed
Nov 8, 2026
sidney-Hung
force-pushed
the
lobby-blocked-storage
branch
from
November 8, 2026 02:33
d6acc77 to
46f192b
Compare
sidney-Hung
force-pushed
the
lobby-blocked-storage
branch
from
November 8, 2026 02:52
46f192b to
e7d2195
Compare
jserv
reviewed
Nov 8, 2026
Where site data is blocked, reading the sessionStorage global throws. The lobby's Start handler named the global in the arguments of its storage helpers, so the throw came before any helper could answer it, and the only trace was the browser's exception in an error line inside a collapsed section: Start looked like it did nothing. d5ad668 gave the interview page storageArea() for this, and the helpers already accept the null it answers, so Practice without selected grounding now reaches the interview, as the interview page expects. A server that requires sign-in cannot admit a candidate whose session cookie is refused, so when nobody is signed in the account line says why as soon as the session answers, and Start stays on the lobby without calling /api/login; Use GitHub and Enter in the username field still sign in where only storage is blocked. This assumes a blocked session storage means blocked cookies. Until the session answers Start waits, and a failed check offers the account retry instead of navigating, because either could hide such a server. A practice focus the candidate ticked to share is not carried: storeSharedFocus holds an unshared focus to be the safe outcome, and a refusal would land in the collapsed section. Selected grounding can only travel through storage, and Strict cannot run without it, so both stay on the lobby and that line now holds their own reason instead of the browser's exception. The section stays collapsed, so a Strict candidate still has to open it to read the reason. Change-Id: If597e1f145134c8d887f4a97db9dd356f3f18a28
Naming localStorage or sessionStorage throws where site data is blocked, and works everywhere else, so the bug passes every local run: it stopped the interview page from loading until d5ad668 and left the lobby's Start doing nothing visible. The lint gate now refuses the names under web/ and points at storageArea(), which answers null instead. web/history.js moves to it through a helper that throws when no store can be reached, because its callers tell a failed delete from an empty store by that throw: each catch still reports the failure, so its results do not change. web/peer-lobby.js keeps its five references, each behind its own disable directive with the reason beside the first: it has the same failure, at module scope when opened from an invite, and fixing it means choosing where an invite token lives without storage, not a rename. Unused directives are errors, so each fix removes its own. Close sysprog21#600 Change-Id: I799b1c07616a3689121d633cb17d9c26b07ae41f
sidney-Hung
force-pushed
the
lobby-blocked-storage
branch
from
November 8, 2026 03:31
e7d2195 to
9842083
Compare
Contributor
|
Thank @sidney-Hung for contributing! |
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 and behavior
Where site data is blocked, reading the
sessionStorageglobal throws. The lobby's Start handler named the global in the arguments of its storage helpers, so the exception came before any helper could handle it. Its message landed in#grounding-error, inside a collapsed<details>, and Start looked like it did nothing.After this change, Practice without grounding opens the interview with storage unreachable. With grounding selected, Practice shows the existing "Clear grounding to start normally" message, since the packet can only reach the interview page through storage. When Practice starts without grounding, a ticked "share this focus" choice is not carried:
storeSharedFocus()already treats a failed write as an unshared focus, and a refusal would land in the collapsed section like the original bug. Strict still stays on the lobby because it cannot run without storage, and#grounding-errornow holdsstorageErrorinstead of the raw exception text.A real browser block also refuses the session cookie. On a server that admits guests, Practice reaches the interview. On a server that requires sign-in, with nobody signed in and session storage unreachable, the lobby says in
#account-statusas soon as the session answers: "Signing in needs site data, which this browser is blocking for this site. Allow site data for this site, then reload this page." Start stays on the lobby with its choices kept, and pressing it moves focus to the sign-in field, which hasaria-describedby="account-status", so the reason is read with the field and is on screen at narrow widths. Without that guard, the storage fix alone would send the candidate to the interview page, which finds nobody signed in and bounces back to a reset lobby. Enter in the sign-in field and the Use GitHub button both still sign in, so a block on storage alone, with cookies working (Firefox'sdom.storage.enabled=falsemay produce this; I have not checked), keeps a way in by keyboard or mouse; there the site-data message is not accurate. Under a full block the login request succeeds but no session follows, and#account-statusshows "GitHub username recorded, but no signed-in session was found. Try signing in again." in place of the reason until a reload.That guard needs the session state, which is unknown until
/api/sessionanswers. With session storage unreachable, Start is held while the answer is pending, without the site-data message since the server may still admit guests, and is released when it arrives. If the check fails with no login attempted,loginResultbecomes"unchecked": Start stays held, the account row offers "Retry account check" with a message that does not mention signing in, the retry stays a GET, and Log out stays hidden. The cost: with storage blocked and the check failing, a guest also waits for a successful retry before Start.A storage global named directly, or read as
.localStorageor.sessionStorageon any object, underweb/now fails ESLint, apart from five existing references marked one by one, described below.Limits, not changed here:
From reading the code, once Start reaches the interview with storage unreachable, some existing choices do not survive, as before for any page without storage: the "Show the LeetCode problem" tick, lobby settings after returning, candidate cases on reload, and in-interview preferences. The grounding refusal is also hidden if the candidate closed the section again before pressing Start.
Strict visibility: the
storageErrortext stays hidden while the<details>is collapsed. Where to show a storage failure is an open question in #600, so this change leaves the<details>as it is.web/peer-lobby.jshas the same failure, at module scope when opened from an invite link, and its fix needs a decision about where the invite token lives once the page has removed it from the URL. Its five references each carry their owneslint-disable-next-line no-restricted-globals, andreportUnusedDisableDirectivesis an error, so a sixth reference fails and each fix removes its own directive. I will open a follow-up issue for it, as agreed in review, and another to movestorageArea,readStoredandwriteStoredtoweb/storage.jsso the lint message no longer points at the audio module.Approach
The first commit resolves
storageArea("sessionStorage"), added in d5ad668, once at module scope intotabStorage, withtabStorageBlockedderived from it, since the block lifts only on reload. The Start handler andclearGroundingpasstabStorageto their storage helpers, which already handle the null it can be. It also adds the site-data reason and the Start guard above, the hold while the session is pending, and the"unchecked"value ofloginResultfor a failed check, all only when session storage is unreachable.tests/browser/account.test.jsasserted the call text, so it now matches each call throughtabStorageand thattabStorageis bound tostorageArea("sessionStorage").tests/browser/lobby-render.test.jspinned the old failed-check state and relied on the runtime having no storage globals; it now makes bothlocalStorageandsessionStoragethrow before importing/app.js, and expects the new state. New lobby tests cover Start with storage unreachable in Practice, in Practice with grounding selected, in Practice with a shared focus ticked, in Strict, on a server that requires sign-in (the reason before Start, Enter reaching/api/loginlike the button, and focus at a 375-pixel width), while the session check is pending, and after it fails, including that Log out stays hidden and that a retry on a guest server does not ask for a sign-in that never happened. They makesessionStoragethrow while cookies andlocalStoragestill work, a partial block rather than a real browser setting. Most of the commit's size is these tests.The second commit adds
no-restricted-globalsandno-restricted-propertiesfor both storage names, with a message namingweb/audio-output.js, and converts the seven references inweb/history.js. They go through a smalldeviceStorage()helper that throws when no store can be reached, so each caller'scatchstill reports the failure and their results do not change. A new test checks thatdeleteReportstill answers "failed" and "account-deleted-local-failed" with storage unreachable; it also passes onmain, where the bare global throws inside the sametry, and guards against a conversion that passes the null through. ThestorageArea()doc comment inweb/audio-output.jsnow says that a caller that must tell a failure from an empty store has to check for null itself, which is whatdeviceStorage()does. The rules apply toweb/**/*.jsonly; the review workbench is a local developer tool that does not importaudio-output.js.Validation
Each new Start test fails without its part of the change and passes with it. The
deleteReporttest fails when the null fromstorageArea()is passed through instead ofdeviceStorage(), and passes with it.npx eslint .passes across the repository, and reintroducing the module-scope read d5ad668 removed fails it atweb/interview.js:480. A script also ran Start in Chromium with its real block-site-data setting: on a server that requires sign-in it stays on the lobby with the message above, and after allowing site data the open page still threw until it was reloaded, which is why the message asks for a reload.Locally,
interview-scroll.test.jsfails the same way at the base commit on this machine.review-memory-testsneeds a newerghthan the one installed, andshell-syntaxflagsscripts/git-post-commit.sh; this change touches neither.local-recorder.test.jsfailed once in a full browser lane and passed six of six runs alone, on this branch and onmain; this change does not touch the files it covers.Not checked: Firefox, the hold and retry states under a real browser block, and the real interview page under a real block on a server that admits guests. Pressing Start again rewrites the same reason, so a screen reader may not announce the repeat, though the field's description now carries it.
Close #600
Written for commit 8a49e07. Summary will update on new commits.