""" A sign-out during a token renewal must not leave half a session behind. A tab left open overnight is exactly this race: the idle watch signs the browser out at the same moment the renewal fires — the hub's log has the two requests one second apart. `refreshAccessToken` came back to an `_auth` that was already null and wrote `{ ..._auth, token, refreshToken }`. Spreading null is silent, so what landed in localStorage was a token with **no identity at all**. That object is worse than no session. The app believes it is one, renders the signed-in interface from it, and throws on the first field it reads — `user.username[0]`, which is "Cannot read properties of undefined (reading '0')". Every load afterwards is blank, and because it is stored it survives reloads, clearing the cache and restarting the device. Reported from a phone, diagnosed from a screenshot of `boot-guard.js` naming the error on screen. Two fixes, and both are needed: the sign-out now wins the race, and `loadAuth` treats an identity-less object as signed out, so a browser already holding one heals on its next load instead of needing someone to find the reset button. """ import json import shutil import subprocess import sys from pathlib import Path import pytest HARNESS = Path(__file__).parent / "harness" / "auth_race_probe.py" @pytest.fixture(scope="module") def out(): if shutil.which("google-chrome") is None: pytest.skip("Chrome is not available") proc = subprocess.run([sys.executable, str(HARNESS)], capture_output=True, text=True, timeout=120) data = json.loads(proc.stdout) assert "error" not in data, f"probe failed: {proc.stdout}{proc.stderr}" return data def test_a_sign_out_during_a_renewal_wins(out): # Not "writes something harmless": writes nothing. The sign-out is the # later intention and there is nothing in a renewal worth keeping over it. assert out["afterTheRace"] is None, ( f"a session survived the sign-out: {out['afterTheRace']}") def test_what_used_to_be_written_is_recognised_as_not_a_session(out): # The healing half. Without it every browser already holding one stays # blank for a year, and the only way out is a menu nobody finds. assert out["poisonedLoads"] is None, out["poisonedLoads"] assert out["poisonedLeftBehind"] is None, ( "the identity-less object was left in storage to be read again") def test_a_real_session_still_loads_untouched(out): # The guard above must not sign anybody out. This is the case that says so. assert out["goodLoads"] == "someone", out["goodLoads"] assert out["goodLeftAlone"], "a valid session was cleared"