J405: red browser specs on dev (docs-palette, toast-stack, palette-polish, addhost-wizard cascade) #442

Open
opened 2026-11-09 03:15:24 +00:00 by kayg · 11 comments
Owner

J405: fix the browser specs found red on unmodified dev by J401 (#345, comment 88223): docs-palette x4, toast-stack x2, palette-polish touch x2, addhost-wizard cascade (42 cases in a combined run). For each, decide product vs spec, fix the root cause, red-first, no weakened assertions, no fixed sleeps. Branch fix-dev-red-specs-2, base 966c52e070.

J405: fix the browser specs found red on unmodified dev by J401 (#345, comment 88223): docs-palette x4, toast-stack x2, palette-polish touch x2, addhost-wizard cascade (42 cases in a combined run). For each, decide product vs spec, fix the root cause, red-first, no weakened assertions, no fixed sleeps. Branch fix-dev-red-specs-2, base 966c52e070b2476aa0e17e9f8413d23a451c38d1.
Author
Owner

Start. Branch fix-dev-red-specs-2, base 966c52e07 (origin/dev).
Plan (est. 3-4 h, mostly slot waits): (1) run each red spec alone on dev-02 on a production build to confirm; (2) read failure + bisect if product; (3) fix red-first; (4) combined-run isolation for addhost-wizard; (5) 3x alone + combined at 1440x900 and 393x852; (6) verify quick.

Start. Branch `fix-dev-red-specs-2`, base 966c52e07 (origin/dev). Plan (est. 3-4 h, mostly slot waits): (1) run each red spec alone on dev-02 on a production build to confirm; (2) read failure + bisect if product; (3) fix red-first; (4) combined-run isolation for addhost-wizard; (5) 3x alone + combined at 1440x900 and 393x852; (6) verify quick.
Author
Owner

Progress: issue opened, tree synced to dev-02 (~/worktrees/j405), first baseline run (docs-palette, toast-stack, palette-polish alone on dev 966c52e07, production build) is queued for a build slot (position 2; all 3 slots busy). Static reading so far: the toast-stack failures look like a measurement taken mid-transition (.ui-toast animates transform/height/width over 190 ms and the spec reads boundingBox() right after the count check). Will confirm with the run before changing anything. Log: dev-02 ~/j405/logs/base1.log.

Progress: issue opened, tree synced to dev-02 (`~/worktrees/j405`), first baseline run (docs-palette, toast-stack, palette-polish alone on dev 966c52e07, production build) is queued for a build slot (position 2; all 3 slots busy). Static reading so far: the toast-stack failures look like a measurement taken mid-transition (`.ui-toast` animates transform/height/width over 190 ms and the spec reads `boundingBox()` right after the count check). Will confirm with the run before changing anything. Log: dev-02 `~/j405/logs/base1.log`.
Author
Owner

Finding 1 (reproduced, dev 966c52e07, production build, dev-02, log ~/j405/logs/base1.log): the 8 reds are real and deterministic when run alone: docs-palette x4, toast-stack x2, palette-polish touch x2.

  • docs-palette: spec unchanged since #311 (7dd462e9e), so this looks like a product regression. This run failed at data-active on the multiplexer window (window is still data-parked, h1 present); J401's run failed one step earlier. Bisecting dev first-parent merges 7dd462e9e..966c52e07 with git bisect run.
  • toast-stack: stack boxes read with boundingBox() right after the count check, while the card's transform/height/width are still transitioning (190 ms). Probe pending to prove it; if so the spec waits for animations to finish (no sleep).
  • palette-polish: label deploy is 57.87 px wide, scrollWidth is an integer, tolerance is -1 px. Probe pending (range width vs scrollWidth).
  • addhost-wizard: in the 13-spec command addhost-wizard runs FIRST (Playwright list order), so the cascade is not caused by an earlier spec; failures start at its 14th case. Capturing the first error with --max-failures=3.

Because the slot queue is 7 deep, everything above is one queued single-slot script (~/j405/all.sh, log ~/j405/logs/all.log).

Finding 1 (reproduced, dev 966c52e07, production build, dev-02, log `~/j405/logs/base1.log`): the 8 reds are real and deterministic when run alone: docs-palette x4, toast-stack x2, palette-polish touch x2. - docs-palette: spec unchanged since #311 (7dd462e9e), so this looks like a product regression. This run failed at `data-active` on the multiplexer window (window is still `data-parked`, h1 present); J401's run failed one step earlier. Bisecting dev first-parent merges 7dd462e9e..966c52e07 with `git bisect run`. - toast-stack: stack boxes read with `boundingBox()` right after the count check, while the card's transform/height/width are still transitioning (190 ms). Probe pending to prove it; if so the spec waits for animations to finish (no sleep). - palette-polish: label `deploy` is 57.87 px wide, `scrollWidth` is an integer, tolerance is -1 px. Probe pending (range width vs scrollWidth). - addhost-wizard: in the 13-spec command addhost-wizard runs FIRST (Playwright list order), so the cascade is not caused by an earlier spec; failures start at its 14th case. Capturing the first error with `--max-failures=3`. Because the slot queue is 7 deep, everything above is one queued single-slot script (`~/j405/all.sh`, log `~/j405/logs/all.log`).
Author
Owner

Finding 2 (bisect, evidence ~/j405/logs/bisect-steps.log + bisect.log on dev-02): docs-palette "desktop ink" is green at 7dd462e9e and red from a6d0223bf, Merge settings-rows-j132 (#304) (first-parent bisect, 8 steps; last good 600ae5eb1). So it is a product regression, not the spec: the spec has not changed since #311. Candidate cause inside #304: the camera/active-window rules for views of rows (camera/lock.ts settled/follow, onRest, windowInView). A probe of camera + active window after a docs page is opened from ⌘K is queued (single slot, ~/j405/logs/all2.log).

Finding 3 (not reproduced as a cascade): in a dev-02 run of the 13-spec command on dev (log ~/j405/logs/all.log, ### combined), addhost-wizard ran first (Playwright runs files alphabetically) and 57 of 58 passed. The one failure is a real spec race: after Back, the page being left (is-leaving, inert) and the new progress page both match .ah-page[data-page='progress'], so toBeVisible() throws a strict-mode violation. J401's cascade was on J401's own part-2 tree and showed an EMPTY <main> with .cl-mockup absent. In the double, a page load only mints a session while previewSignedOut is false, and /auth/logout sets it globally; only /__mock/reset clears it, and addhost-wizard never calls that. Repro (a scratch spec that signs out, then addhost-wizard) is queued.

Finding 2 (bisect, evidence `~/j405/logs/bisect-steps.log` + `bisect.log` on dev-02): docs-palette "desktop ink" is green at 7dd462e9e and red from **a6d0223bf, Merge settings-rows-j132 (#304)** (first-parent bisect, 8 steps; last good 600ae5eb1). So it is a product regression, not the spec: the spec has not changed since #311. Candidate cause inside #304: the camera/active-window rules for views of rows (`camera/lock.ts` `settled`/`follow`, `onRest`, `windowInView`). A probe of camera + active window after a docs page is opened from ⌘K is queued (single slot, `~/j405/logs/all2.log`). Finding 3 (not reproduced as a cascade): in a dev-02 run of the 13-spec command on dev (log `~/j405/logs/all.log`, `### combined`), addhost-wizard ran first (Playwright runs files alphabetically) and 57 of 58 passed. The one failure is a real spec race: after Back, the page being left (`is-leaving`, inert) and the new progress page both match `.ah-page[data-page='progress']`, so `toBeVisible()` throws a strict-mode violation. J401's cascade was on J401's own part-2 tree and showed an EMPTY `<main>` with `.cl-mockup` absent. In the double, a page load only mints a session while `previewSignedOut` is false, and `/auth/logout` sets it globally; only `/__mock/reset` clears it, and addhost-wizard never calls that. Repro (a scratch spec that signs out, then addhost-wizard) is queued.
Author
Owner

Findings so far, all on dev 966c52e07 (production build, dev-02). Branch fix-dev-red-specs-2, head e7629c960, pushed.

spec cause evidence
palette-polish touch x2 spec: read the palette rect mid scale-in (palette opens 240 ms, scale 0.98→1; deploy label 57.866 vs 58.306 at rest, probe ~/j405/logs/all.log ### probe) green after fix, 3x
toast-stack x2 spec: boxes read while cards ease to the front card's size (190 ms) green after fix, 3x; the transition timeline probe failed on an unfinishable animation, so the cause is by inference + red/green, not by a recorded timeline
docs-palette x4 spec out of date, found by bisect: green at 7dd462e9e, red from a6d0223bf (#304 Settings as rows). Enter on "infraternal multiplexer" now opens the Settings window s-terminal-multiplexer (new setting "Offer To Switch" mentions it); the palette has no ranking and lists Settings before Docs (probe ~/j405/logs/all2.log ### probe2). Product works as designed green after fix, 3x
addhost-wizard cascade shared double state (spec side): one global preview sign-out flag survives; only /__mock/reset clears it and addhost-wizard never called it. Scratch repro: sign-out spec then addhost-wizard → .cl-mockup not found after 45 s (J401's exact signature) on the original file, passes with the fix (~/j405/logs/all3.log). The exact J401 cascade did NOT reproduce on unmodified dev (57/58 in the combined run), so this is the matching hazard, not a proven account of that run. Also one real spec race (strict-mode on the leaving page)

Commits: 92b8fb027 palette-polish (+ test/motion.ts helper), abd72b250 toast-stack, 7e6d9ef90 docs-palette, 0d51cca83 addhost reset, e7629c960 addhost leaving page.
Proof so far: docs-palette + toast-stack + palette-polish, --repeat-each=3, 120 passed (~/j405/logs/three1.full.log). Pending: verify quick, addhost-wizard x3, 13-spec combined run on the final head.
Question for kayg (not blocking): should the palette rank a docs page whose title matches the query above a Settings row that only mentions it? Today it does not rank at all.

Findings so far, all on dev 966c52e07 (production build, dev-02). Branch `fix-dev-red-specs-2`, head e7629c960, pushed. | spec | cause | evidence | |---|---|---| | palette-polish touch x2 | **spec**: read the palette rect mid scale-in (palette opens 240 ms, scale 0.98→1; `deploy` label 57.866 vs 58.306 at rest, probe `~/j405/logs/all.log` `### probe`) | green after fix, 3x | | toast-stack x2 | **spec**: boxes read while cards ease to the front card's size (190 ms) | green after fix, 3x; the transition timeline probe failed on an unfinishable animation, so the cause is by inference + red/green, not by a recorded timeline | | docs-palette x4 | **spec out of date, found by bisect**: green at 7dd462e9e, red from a6d0223bf (#304 Settings as rows). Enter on "infraternal multiplexer" now opens the Settings window `s-terminal-multiplexer` (new setting "Offer To Switch" mentions it); the palette has no ranking and lists Settings before Docs (probe `~/j405/logs/all2.log` `### probe2`). Product works as designed | green after fix, 3x | | addhost-wizard cascade | **shared double state (spec side)**: one global preview sign-out flag survives; only `/__mock/reset` clears it and addhost-wizard never called it. Scratch repro: sign-out spec then addhost-wizard → `.cl-mockup` not found after 45 s (J401's exact signature) on the original file, passes with the fix (`~/j405/logs/all3.log`). The exact J401 cascade did NOT reproduce on unmodified dev (57/58 in the combined run), so this is the matching hazard, not a proven account of that run. Also one real spec race (strict-mode on the leaving page) | | Commits: 92b8fb027 palette-polish (+ test/motion.ts helper), abd72b250 toast-stack, 7e6d9ef90 docs-palette, 0d51cca83 addhost reset, e7629c960 addhost leaving page. Proof so far: docs-palette + toast-stack + palette-polish, `--repeat-each=3`, 120 passed (`~/j405/logs/three1.full.log`). Pending: `verify quick`, addhost-wizard x3, 13-spec combined run on the final head. Question for kayg (not blocking): should the palette rank a docs page whose title matches the query above a Settings row that only mentions it? Today it does not rank at all.
Author
Owner

Progress, head 6e1f30cc9 (pushed). Evidence on dev-02: ~/j405/logs/.

  • scripts/verify quick: exit 0 (all6.log; first run flagged a missing doc comment on open, fixed).
  • docs-palette + toast-stack + palette-polish, --repeat-each=3: 120 passed (three1.full.log, on 5a-era head; test code of these three files unchanged since).
  • addhost-wizard --repeat-each=3: two earlier runs each had 1 failure of 174, the same class both times (strict-mode violation: the is-leaving copy of the progress page and its job rows). Fixed in the last commit for every case that reads the progress page after Back; then 174/174 passed (addhost3c.full.log).
  • Running now: the 13-spec combined command + toast-stack + palette-polish on this head (comb2).
Progress, head 6e1f30cc9 (pushed). Evidence on dev-02: `~/j405/logs/`. - `scripts/verify quick`: exit 0 (`all6.log`; first run flagged a missing doc comment on `open`, fixed). - docs-palette + toast-stack + palette-polish, `--repeat-each=3`: 120 passed (`three1.full.log`, on 5a-era head; test code of these three files unchanged since). - addhost-wizard `--repeat-each=3`: two earlier runs each had 1 failure of 174, the same class both times (strict-mode violation: the `is-leaving` copy of the progress page and its job rows). Fixed in the last commit for every case that reads the progress page after Back; then 174/174 passed (`addhost3c.full.log`). - Running now: the 13-spec combined command + toast-stack + palette-polish on this head (`comb2`).
Author
Owner

Scope added by the orchestrator: sign-out x2 (J404, #426). Both reproduce in J404's logs on dev 966c52e07 (~claude/j404-evidence/dev-specs.log).

  • "the palette has Sign out; it asks, then signs out": product bug. showTerminal() in main.ts awaits TerminalClient.open() and then keeps the client without re-checking sessionGeneration. A sign-out during the connect runs endSession() while currentTerminal is still undefined, so the late client is never disposed: a live terminal and the test hook survive sign-out. Fix: one generation check after the await, dispose the late client.
  • "D245: ... every storage area": spec out of date. D312 made the server the only saved layout; nothing writes infraternal.canvas.<id> into the browser, so the poll for it times out. The sweep itself (clearAccountStorage) is unchanged. The spec now seeds the earlier build's keys under the real account id and keeps every assertion after the setup.
    Both are committed on the branch (red = the existing specs on dev; green run queued after the combined run releases my slot).
Scope added by the orchestrator: `sign-out` x2 (J404, #426). Both reproduce in J404's logs on dev 966c52e07 (`~claude/j404-evidence/dev-specs.log`). - "the palette has Sign out; it asks, then signs out": **product bug**. `showTerminal()` in `main.ts` awaits `TerminalClient.open()` and then keeps the client without re-checking `sessionGeneration`. A sign-out during the connect runs `endSession()` while `currentTerminal` is still undefined, so the late client is never disposed: a live terminal and the test hook survive sign-out. Fix: one generation check after the await, dispose the late client. - "D245: ... every storage area": **spec out of date**. D312 made the server the only saved layout; nothing writes `infraternal.canvas.<id>` into the browser, so the poll for it times out. The sweep itself (`clearAccountStorage`) is unchanged. The spec now seeds the earlier build's keys under the real account id and keeps every assertion after the setup. Both are committed on the branch (red = the existing specs on dev; green run queued after the combined run releases my slot).
Author
Owner

Finish. Branch fix-dev-red-specs-2, head b5a047adc (pushed, git ls-remote confirms), 8 commits on origin/dev 54a9da2a8. Logs and reports: dev-02 ~/j405/logs/.

Cause per spec:

  • palette-polish touch x2: spec (read the palette mid 240 ms scale-in).
  • toast-stack x2: spec (read the stack mid 190 ms transitions; cause by inference plus red/green).
  • docs-palette x4: spec out of date; bisect: green 7dd462e9e, red from a6d0223bf (#304). Enter on "infraternal multiplexer" now opens a Settings row; the palette has no ranking.
  • addhost-wizard cascade: spec/shared double state. Global preview sign-out flag cleared only by /__mock/reset; addhost-wizard never called it. Repro (sign-out spec first): .cl-mockup not found after 45 s on the original, passes with the fix. J401's exact 42-case cascade did not reproduce on dev; it was on J401's own part-2 tree. Plus a real spec race: after Back the is-leaving copy of the progress page and its job rows match twice (1 in 174 on three runs).
  • sign-out "palette has Sign out": product bug. showTerminal() kept a terminal client that finished connecting after sign-out (no generation check after the await): a live terminal and test hook survive sign-out. Red: new deterministic test (holds the wasm module until sign-out) fails on dev with "no connection is left open after sign-out"; 6/6 green with the one-line fix.
  • sign-out "D245": spec out of date (D312: no account key is written to the browser; caches must be empty is stale since #243, the worker's cache holds only public app-shell files). Spec now seeds the old build's keys and checks the cache holds only public files.

Gate results:

  • verify quick exit 0 on this tree (quick15.full.log). Not verify fast (no Rust changed).
  • docs-palette, toast-stack, palette-polish, sign-out, --repeat-each=3: 161 passed, 1 failed on an earlier head (D245's racy split step, since removed) — four3.full.log.
  • addhost-wizard --repeat-each=3: 174/174 (addhost3c.full.log), on 966c52e07 base with identical spec files.
  • 13-spec combined command + toast-stack + palette-polish + sign-out, one run, head b5a047adc: 196 passed, 0 failed (comb3.full.log).
  • sign-out --repeat-each=3 on b5a047adc: 38 passed, 4 failed, all "Could not read this server's name" in the two real-cookie cases' setup in repeats 1 and 2 (so3.full.log). Not reproduced in 12 + 12 further runs on plain dev and on the head (so-dev6, so-head6); the error is raised before any code I changed. Treat as an unexplained transient of the double; I did not find its cause.
    Specs run at 1440x900 and 393x852 inside the specs themselves (production build).

For kayg: should the palette rank a docs page whose title matches above a Settings row that only mentions it? Not changed.

Finish. Branch `fix-dev-red-specs-2`, head **b5a047adc** (pushed, `git ls-remote` confirms), 8 commits on origin/dev 54a9da2a8. Logs and reports: dev-02 `~/j405/logs/`. Cause per spec: - palette-polish touch x2: **spec** (read the palette mid 240 ms scale-in). - toast-stack x2: **spec** (read the stack mid 190 ms transitions; cause by inference plus red/green). - docs-palette x4: **spec out of date**; bisect: green 7dd462e9e, red from a6d0223bf (#304). Enter on "infraternal multiplexer" now opens a Settings row; the palette has no ranking. - addhost-wizard cascade: **spec/shared double state**. Global preview sign-out flag cleared only by `/__mock/reset`; addhost-wizard never called it. Repro (sign-out spec first): `.cl-mockup` not found after 45 s on the original, passes with the fix. J401's exact 42-case cascade did not reproduce on dev; it was on J401's own part-2 tree. Plus a real spec race: after Back the `is-leaving` copy of the progress page and its job rows match twice (1 in 174 on three runs). - sign-out "palette has Sign out": **product bug**. `showTerminal()` kept a terminal client that finished connecting after sign-out (no generation check after the await): a live terminal and test hook survive sign-out. Red: new deterministic test (holds the wasm module until sign-out) fails on dev with "no connection is left open after sign-out"; 6/6 green with the one-line fix. - sign-out "D245": **spec out of date** (D312: no account key is written to the browser; `caches` must be empty is stale since #243, the worker's cache holds only public app-shell files). Spec now seeds the old build's keys and checks the cache holds only public files. Gate results: - `verify quick` exit 0 on this tree (`quick15.full.log`). Not `verify fast` (no Rust changed). - docs-palette, toast-stack, palette-polish, sign-out, `--repeat-each=3`: 161 passed, 1 failed on an earlier head (D245's racy split step, since removed) — `four3.full.log`. - addhost-wizard `--repeat-each=3`: 174/174 (`addhost3c.full.log`), on 966c52e07 base with identical spec files. - 13-spec combined command + toast-stack + palette-polish + sign-out, one run, head b5a047adc: 196 passed, 0 failed (`comb3.full.log`). - sign-out `--repeat-each=3` on b5a047adc: 38 passed, 4 failed, all "Could not read this server's name" in the two real-cookie cases' setup in repeats 1 and 2 (`so3.full.log`). Not reproduced in 12 + 12 further runs on plain dev and on the head (`so-dev6`, `so-head6`); the error is raised before any code I changed. Treat as an unexplained transient of the double; I did not find its cause. Specs run at 1440x900 and 393x852 inside the specs themselves (production build). For kayg: should the palette rank a docs page whose title matches above a Settings row that only mentions it? Not changed.
Author
Owner

Review of fix-dev-red-specs-2 @ b5a047adc (8 commits on origin/dev 54a9da2a8)

Verdict: APPROVE. The sign-out fix works: across every path I probed, nothing live survives sign-out. One P2 is worth fixing, small and cheap: the generation check runs after the late client has already opened a WebSocket. I did not find a spec change that hides a product bug.

Logs (dev-02, ~/r442/logs/): probes.full.log, combined.full.log, flake.full.log, flakediag.full.log, quick2.full.log. The probe specs are in ~/r442/probes/ and were never committed. They ran on a production build (the same playwright.config.ts webServer) at 1440×900 and 393×852 touch.

Runs

  • Combined specs on the head (addhost-wizard, docs-palette, palette-polish, sign-out, toast-stack; both viewports are inside the specs): 112 passed, 0 failed, 20.1 min.
  • verify quick (VERIFY_QUICK_BASE=origin/dev): PASS, all 10 rows. My first run failed on my own untracked probe files (missing doc comments and // sleep: reasons). I moved them out of the worktree and reran. The brief says reviewers should not run quick; I ran it only because the task asked for it.

Security fix: is it complete?

I probed these on the production build, 12 cases (6 probes × 2 viewports):

Probe Result
A. Clusters mock, wasm held until after sign-out, then released live sockets 0, hook gone, no windows, no ?session= in the URL. But 1 socket was created after sign-out (desktop). Phone saw 0, so it depends on timing. See P2-1.
B. Real cookie, product canvas, wasm held past sign-out 0 sockets created after sign-out, 0 live, no windows.
C. Connection dropped, then sign-out during the reconnect backoff 0 sockets created in the next 8 s. The closed guards in retryStream and the timer callback work.
D. OSC 52 in flight at sign-out, and sent after it 0 clipboard writes, 0 toasts.
E. Toast with a pending timer at sign-out 0 toasts on the sign-in screen after 2.5 s.
F. Sign-out right after the canvas opens, then check caches 0 sockets after, 0 live. The only cache is infraternal-drawing-v1, holding / plus .js, .css, .woff2 and .wasm paths. No query strings and no account data in the paths.

Static reading: live.ts:332 (canvas windows) and product.ts:211 (isCurrent after store.load()) have the same late-arrival guard. The service worker caches only public app-shell files.

Findings

P2-1: the late client still opens a socket after sign-out. main.ts:632 checks the generation after TerminalClient.open() returns. By then new TerminalClient(...) (terminal.ts:572, constructor at ~529) has already built a MuxConnection and called openStream. Probe A, desktop: sockets created after sign-out = 1, closed at once. Nothing lives on, and the cookie is already cleared by logout, so the upgrade should be refused. Still, "no connection after sign-out" is the property to hold. Suggested fix: pass an isCurrent callback to TerminalClient.open, and check it after prepareResources and the setTimeout(0) turn, before constructing. Keep the dispose at main.ts:632 as the backstop. The new test accepts "closes straight away or never connects", so it cannot see this. A strict version is probe A's last assertion (afterMark(t) === 0).

P3-1: the new test's assertions are weak. sign-out.spec.ts ends with expect.poll(closedAfterRelease)....catch(() => undefined), which can never fail. live() === 0 and hook === false do catch the original bug (the author's red run shows this). A stricter test would also record socket creation time against the sign-out time.

P3-2: other stale-async paths in showTerminal have no generation guard (read, not probed):

  • main.ts:492-496: the catch around loadFont and mountCoreScreen calls renderUnavailable. If a font fetch fails after a sign-out from another tab (the BroadcastChannel path, endSession), "Connect to load your layout" replaces the sign-in screen. Try again recovers it.
  • main.ts:509,521,522 (clusters and canvas preview modes only, gated by __CLUSTERS_PREVIEW__): canvasPrototype is assigned after an await with no check.
  • main.ts:674-677: the final catch writes into #connection-status without checking the generation. This is harmless today.

P3-3: motionSettled has no upper bound (test/motion.ts). It waits for any finite animation to end, so a regression to a 600 ms spring would pass silently. Today the CSS is within the owner's rule: the palette uses --t-panel 240 ms, ease-out and --ease-out (style.css:503,512), and toasts use --t-pop 180 ms ease-out (styles.css:199). I read the CSS rather than measuring in the browser. Suggest expect(max endTime of the running animations).toBeLessThanOrEqual(300) inside the helper, so the spec enforces the rule instead of hiding a violation.

P3-4: D245 cache check looks at URLs only. The service worker caches / from a navigation fetch that carries the cookie (offline.worker.ts fetch handler). Today / is static, so it is fine. Suggest the spec also assert that the cached / body does not contain the account id or display name. Separately, the dropped assertion ("this build writes a layout key") is replaced by seeding. I confirmed there is no writer of those keys in src/ apart from the sweep in account-storage.ts. I could not find D245 or D312 defined in DECISIONS.md on this tree (only an "amends D312" mention at line 4304), so I could not check the D312 claim against its text.

Spec-only changes

  • palette-polish (touch): sound. Palette transform: scale(0.98)→1 over 240 ms ease-out. getBoundingClientRect includes the transform, which explains why the label was 57.87 px wide against 58.31 at rest. It is not a layout bug.
  • toast-stack: sound. Cards ease size and offset over 180 ms ease-out. The author said the cause is inferred, not recorded, and I agree it is plausible. The 112-run pass is consistent with it.
  • docs-palette: not hiding a bug in the spec. Enter on "infraternal multiplexer" opens the Settings row "Offer To Switch", because the palette does not rank and lists Settings first (#304). That is a product decision for kayg (the author already asked). I'd make the point that an exact title match losing to a Settings row that merely mentions it is a UX regression candidate. Clicking the row also stops the spec from covering "Enter opens the first Docs hit".
  • addhost-wizard: sound. The double's single global preview sign-out flag is cleared only by /__mock/reset, so each case resets first. onScreen() excludes the inert .is-leaving page. The spec used a bare toBeVisible on two matches before.
  • sign-out D245: see P3-4.

Open flake ("Could not read this server's name", 4 of 42)

I could not reproduce it. I ran sign-out.spec.ts ×5 (70 passed) and a diagnostic copy of the file ×6 with log-on-failure for the banner step (84 passed), so 22 runs of the two real-cookie cases with no failure.

What the code says, without a reproduction:

  • The text is shown only by showTerminal (main.ts:430), when sessionHostname(identity) is empty. The double always returns a hostname, so the only way there is checkSession() returning undefined, which is a 401.
  • In the double, session answers 401 whenever activeAuthCookie no longer matches the page's cookie. The double has one global activeAuthCookie. Any HTML GET of /?proto=… (mock-server.ts:738-745), login-finish, setup-finish or /__mock/reset replaces or clears it. A stray request from another browser or run on the same double between "Open infraternal" and the session check gives exactly this error.
  • The author's failing runs were the second and third repeats, where earlier tests were faster. That suggests a stray request landing in the setup window.
  • A product wart that is real regardless: a 401 from checkSession in showTerminal is reported as "Could not read this server's name" instead of going to the sign-in screen. I'd route identity === undefined to renderAuth.

Not done

  • No verify fast (the brief says reviewers must not run it).
  • No Mac, root, or real-server run; the changes are TypeScript specs plus one line in main.ts.
  • P3-2 is from reading only.
## Review of `fix-dev-red-specs-2` @ **b5a047adc** (8 commits on origin/dev 54a9da2a8) **Verdict: APPROVE.** The sign-out fix works: across every path I probed, nothing live survives sign-out. One P2 is worth fixing, small and cheap: the generation check runs after the late client has already opened a WebSocket. I did not find a spec change that hides a product bug. Logs (dev-02, `~/r442/logs/`): `probes.full.log`, `combined.full.log`, `flake.full.log`, `flakediag.full.log`, `quick2.full.log`. The probe specs are in `~/r442/probes/` and were never committed. They ran on a production build (the same `playwright.config.ts` webServer) at 1440×900 and 393×852 touch. ### Runs - **Combined specs on the head** (addhost-wizard, docs-palette, palette-polish, sign-out, toast-stack; both viewports are inside the specs): **112 passed, 0 failed, 20.1 min**. - **`verify quick`** (`VERIFY_QUICK_BASE=origin/dev`): **PASS**, all 10 rows. My first run failed on my own untracked probe files (missing doc comments and `// sleep:` reasons). I moved them out of the worktree and reran. The brief says reviewers should not run `quick`; I ran it only because the task asked for it. ### Security fix: is it complete? I probed these on the production build, 12 cases (6 probes × 2 viewports): | Probe | Result | |---|---| | **A.** Clusters mock, wasm held until after sign-out, then released | live sockets 0, hook gone, no windows, no `?session=` in the URL. **But 1 socket was created after sign-out** (desktop). Phone saw 0, so it depends on timing. See P2-1. | | **B.** Real cookie, product canvas, wasm held past sign-out | 0 sockets created after sign-out, 0 live, no windows. | | **C.** Connection dropped, then sign-out during the reconnect backoff | 0 sockets created in the next 8 s. The `closed` guards in `retryStream` and the timer callback work. | | **D.** OSC 52 in flight at sign-out, and sent after it | 0 clipboard writes, 0 toasts. | | **E.** Toast with a pending timer at sign-out | 0 toasts on the sign-in screen after 2.5 s. | | **F.** Sign-out right after the canvas opens, then check caches | 0 sockets after, 0 live. The only cache is `infraternal-drawing-v1`, holding `/` plus `.js`, `.css`, `.woff2` and `.wasm` paths. No query strings and no account data in the paths. | Static reading: `live.ts:332` (canvas windows) and `product.ts:211` (`isCurrent` after `store.load()`) have the same late-arrival guard. The service worker caches only public app-shell files. ### Findings **P2-1: the late client still opens a socket after sign-out.** `main.ts:632` checks the generation after `TerminalClient.open()` returns. By then `new TerminalClient(...)` (`terminal.ts:572`, constructor at ~529) has already built a `MuxConnection` and called `openStream`. Probe A, desktop: `sockets created after sign-out = 1`, closed at once. Nothing lives on, and the cookie is already cleared by `logout`, so the upgrade should be refused. Still, "no connection after sign-out" is the property to hold. Suggested fix: pass an `isCurrent` callback to `TerminalClient.open`, and check it after `prepareResources` and the `setTimeout(0)` turn, before constructing. Keep the dispose at `main.ts:632` as the backstop. The new test accepts "closes straight away or never connects", so it cannot see this. A strict version is probe A's last assertion (`afterMark(t) === 0`). **P3-1: the new test's assertions are weak.** `sign-out.spec.ts` ends with `expect.poll(closedAfterRelease)....catch(() => undefined)`, which can never fail. `live() === 0` and `hook === false` do catch the original bug (the author's red run shows this). A stricter test would also record socket creation time against the sign-out time. **P3-2: other stale-async paths in `showTerminal` have no generation guard** (read, not probed): - `main.ts:492-496`: the `catch` around `loadFont` and `mountCoreScreen` calls `renderUnavailable`. If a font fetch fails after a sign-out from another tab (the BroadcastChannel path, `endSession`), "Connect to load your layout" replaces the sign-in screen. Try again recovers it. - `main.ts:509,521,522` (clusters and canvas preview modes only, gated by `__CLUSTERS_PREVIEW__`): `canvasPrototype` is assigned after an await with no check. - `main.ts:674-677`: the final catch writes into `#connection-status` without checking the generation. This is harmless today. **P3-3: `motionSettled` has no upper bound** (`test/motion.ts`). It waits for any finite animation to end, so a regression to a 600 ms spring would pass silently. Today the CSS is within the owner's rule: the palette uses `--t-panel` 240 ms, `ease-out` and `--ease-out` (`style.css:503,512`), and toasts use `--t-pop` 180 ms ease-out (`styles.css:199`). I read the CSS rather than measuring in the browser. Suggest `expect(max endTime of the running animations).toBeLessThanOrEqual(300)` inside the helper, so the spec enforces the rule instead of hiding a violation. **P3-4: D245 cache check looks at URLs only.** The service worker caches `/` from a navigation fetch that carries the cookie (`offline.worker.ts` fetch handler). Today `/` is static, so it is fine. Suggest the spec also assert that the cached `/` body does not contain the account id or display name. Separately, the dropped assertion ("this build writes a layout key") is replaced by seeding. I confirmed there is no writer of those keys in `src/` apart from the sweep in `account-storage.ts`. I could not find D245 or D312 defined in `DECISIONS.md` on this tree (only an "amends D312" mention at line 4304), so I could not check the D312 claim against its text. ### Spec-only changes - **palette-polish (touch):** sound. Palette `transform: scale(0.98)→1` over 240 ms ease-out. `getBoundingClientRect` includes the transform, which explains why the label was 57.87 px wide against 58.31 at rest. It is not a layout bug. - **toast-stack:** sound. Cards ease size and offset over 180 ms ease-out. The author said the cause is inferred, not recorded, and I agree it is plausible. The 112-run pass is consistent with it. - **docs-palette:** not hiding a bug in the spec. Enter on "infraternal multiplexer" opens the Settings row "Offer To Switch", because the palette does not rank and lists Settings first (#304). That is a product decision for kayg (the author already asked). I'd make the point that an exact title match losing to a Settings row that merely mentions it is a UX regression candidate. Clicking the row also stops the spec from covering "Enter opens the first Docs hit". - **addhost-wizard:** sound. The double's single global preview sign-out flag is cleared only by `/__mock/reset`, so each case resets first. `onScreen()` excludes the inert `.is-leaving` page. The spec used a bare `toBeVisible` on two matches before. - **sign-out D245:** see P3-4. ### Open flake ("Could not read this server's name", 4 of 42) **I could not reproduce it.** I ran `sign-out.spec.ts` ×5 (70 passed) and a diagnostic copy of the file ×6 with log-on-failure for the banner step (84 passed), so 22 runs of the two real-cookie cases with no failure. What the code says, without a reproduction: - The text is shown only by `showTerminal` (`main.ts:430`), when `sessionHostname(identity)` is empty. The double always returns a `hostname`, so the only way there is `checkSession()` returning `undefined`, which is a 401. - In the double, `session` answers 401 whenever `activeAuthCookie` no longer matches the page's cookie. The double has one global `activeAuthCookie`. Any HTML GET of `/?proto=…` (`mock-server.ts:738-745`), `login-finish`, `setup-finish` or `/__mock/reset` replaces or clears it. A stray request from another browser or run on the same double between "Open infraternal" and the session check gives exactly this error. - The author's failing runs were the second and third repeats, where earlier tests were faster. That suggests a stray request landing in the setup window. - A product wart that is real regardless: a 401 from `checkSession` in `showTerminal` is reported as "Could not read this server's name" instead of going to the sign-in screen. I'd route `identity === undefined` to `renderAuth`. ### Not done - No `verify fast` (the brief says reviewers must not run it). - No Mac, root, or real-server run; the changes are TypeScript specs plus one line in `main.ts`. - P3-2 is from reading only.
Author
Owner

Follow-ups on branch signout-followups-442, head 59760ed59 (pushed; git ls-remote confirms), 11 commits on origin/dev 547a48885. Red-first: the five test commits come before their fixes. Evidence on dev-02 ~/j405/logs/ (b-red8, b-green8, b-comb8, b-reg7, bquick7).

  1. P2 TerminalClient.open takes isCurrent, asked after the module and font are ready and before anything is built; false rejects with TerminalOpenCancelled and no connection is made. Test: counts WebSocket constructions in the page (Proxy on the constructor) and requires the count not to move after sign-out, with the wasm held and released; it requires the page marker data-late-terminal="cancelled" (test double only) instead of sleeping. Red on the tests-only head: fails ("cancelled" expected, "none" received); green 3x3.
  2. P3 generation guards added after the remaining awaits in showTerminal (font failure, clusters mockup, canvas prototype and their catches). Not browser-tested: the window is a few ms wide. motionSettled now fails at the first look when a finite animation is over 300 ms (delay+duration+repeats); frame-paced, no sleep. motion-bound.spec.ts: 150 ms passes, 600 ms fails naming the rule, an endless animation is ignored.
  3. 401. showTerminal sends an empty session (401) to sign-in with "Your session ended. Sign in again to continue."; a session without a host name keeps the server-name message. The double now hands out a preview cookie per page load (a set; logout removes only its own, reset clears all; ceremonies still replace the active one). Tests: 401 after setup goes to sign-in; a page loaded in a second context does not end the first's real-cookie session (red on dev: 401).
  4. Palette ranking. palette-rank.ts: a row may carry a title; when a title equals or starts with the query (case and a leading the/a/an ignored), its group is listed first; nothing else moves. Docs page rows carry their title. Unit test (4 cases) plus palette-ranking.spec.ts at 1440x900 and 393x852; docs-palette is back to pressing Enter.

Gates:

  • verify quick: exit 0 (bquick7.full.log, on be4ddf3b3; later commits changed only the marker and a commit message). Not verify fast.
  • Red (tests only): sockets test, 401 test, other-context test, ranking, 300 ms bound all fail; palette-rank unit 4/4 passes only with the module.
  • Green on the final tree: sign-out x3 48 passed; combined (13 specs + toast-stack, palette-polish, sign-out, palette-ranking, motion-bound): 205 passed, 8 skipped, 0 failed (b-comb8); docs-palette/toast-stack/palette-polish x3: 120 passed (b-others6).
  • Auth regression set (auth-binary, onboarding, recovery, device-approval, join-approval, dead-session, ended-strip, stale-screen, snapshot-resume, core-screen, terminal, ...): 86 passed, 4 failed = recovery-ui-hold sign-in screenshot baselines. Those 4 also fail on plain dev bd551e549 (b-base8), so they are not from this branch; not investigated.
  • Not proven: the real-cookie flake itself was never reproduced, so the double change is the likely cause, not a confirmed one. The 401 wording is mine; change it if the owner prefers.
Follow-ups on branch `signout-followups-442`, head **59760ed59** (pushed; `git ls-remote` confirms), 11 commits on origin/dev 547a48885. Red-first: the five test commits come before their fixes. Evidence on dev-02 `~/j405/logs/` (`b-red8`, `b-green8`, `b-comb8`, `b-reg7`, `bquick7`). 1. **P2** `TerminalClient.open` takes `isCurrent`, asked after the module and font are ready and before anything is built; false rejects with `TerminalOpenCancelled` and no connection is made. Test: counts WebSocket constructions in the page (Proxy on the constructor) and requires the count not to move after sign-out, with the wasm held and released; it requires the page marker `data-late-terminal="cancelled"` (test double only) instead of sleeping. Red on the tests-only head: fails ("cancelled" expected, "none" received); green 3x3. 2. **P3** generation guards added after the remaining awaits in `showTerminal` (font failure, clusters mockup, canvas prototype and their catches). Not browser-tested: the window is a few ms wide. `motionSettled` now fails at the first look when a finite animation is over 300 ms (delay+duration+repeats); frame-paced, no sleep. `motion-bound.spec.ts`: 150 ms passes, 600 ms fails naming the rule, an endless animation is ignored. 3. **401.** `showTerminal` sends an empty session (401) to sign-in with "Your session ended. Sign in again to continue."; a session without a host name keeps the server-name message. The double now hands out a preview cookie per page load (a set; logout removes only its own, reset clears all; ceremonies still replace the active one). Tests: 401 after setup goes to sign-in; a page loaded in a second context does not end the first's real-cookie session (red on dev: 401). 4. **Palette ranking.** `palette-rank.ts`: a row may carry a `title`; when a title equals or starts with the query (case and a leading the/a/an ignored), its group is listed first; nothing else moves. Docs page rows carry their title. Unit test (4 cases) plus `palette-ranking.spec.ts` at 1440x900 and 393x852; docs-palette is back to pressing Enter. Gates: - `verify quick`: exit 0 (`bquick7.full.log`, on be4ddf3b3; later commits changed only the marker and a commit message). Not `verify fast`. - Red (tests only): sockets test, 401 test, other-context test, ranking, 300 ms bound all fail; palette-rank unit 4/4 passes only with the module. - Green on the final tree: sign-out x3 48 passed; combined (13 specs + toast-stack, palette-polish, sign-out, palette-ranking, motion-bound): 205 passed, 8 skipped, 0 failed (`b-comb8`); docs-palette/toast-stack/palette-polish x3: 120 passed (`b-others6`). - Auth regression set (auth-binary, onboarding, recovery, device-approval, join-approval, dead-session, ended-strip, stale-screen, snapshot-resume, core-screen, terminal, ...): 86 passed, 4 failed = `recovery-ui-hold` sign-in screenshot baselines. Those 4 also fail on plain dev bd551e549 (`b-base8`), so they are not from this branch; not investigated. - Not proven: the real-cookie flake itself was never reproduced, so the double change is the likely cause, not a confirmed one. The 401 wording is mine; change it if the owner prefers.
Author
Owner

Review of signout-followups-442 @ 59760ed59 (11 commits on origin/dev 547a48885)

Verdict: APPROVE. I found no P0, P1 or P2. Four P3 notes follow; none blocks a merge.

Evidence is on dev-02 in ~/r442b/logs/: specs.log, probes20.log, probesDE.log, quick2.log. The tests ran on a production build through build-slot, from a detached worktree at 59760ed59. The probe spec is J431's zz-review-probes.spec.ts, never committed; I did not change it.

Sign-out: no socket after sign-out

Each probe runs at 1440×900 and at 393×852 with touch, and records every WebSocket created after the moment sign-out finished.

Probe Runs Sockets created after sign-out Live at end
A: clusters mock, wasm held past sign-out, then released 20 × 2 viewports 0 in all 40 0
B: real cookie, product canvas, wasm held 20 × 2 0 in all 40 0
C: connection dropped, sign-out during the reconnect backoff, 8 s wait 20 × 2 0 in all 40 0
F: sign out right after the canvas opens, then check caches 20 × 2 0 in all 40 0
D: OSC 52 in flight, racing and after sign-out 3 × 2 no clipboard writes, no toasts 0
E: toast with a pending timer at sign-out 3 × 2 no toasts on the sign-in screen 0

160 tests ran in 42.5 min (probes20.log, 160 passed). D and E: 12 passed (probesDE.log). Probe A is the one that showed 1 late socket on the desktop at b5a047adc (P2-1 in comment 88876). It is now 0 across 40 runs. The fix is the right one: isCurrent is asked at terminal.ts after the font, the wasm module and the setTimeout(0) turn, before createRenderer and new TerminalClient. The constructor opens the connection, so nothing is built for a dead session. The dispose at main.ts stays as a backstop and sets the marker disposed. The new spec requires the marker cancelled, so it would catch a regression to the backstop path. Its WebSocket Proxy counts constructor calls, so a refused handshake counts too.

Generation guards (P3-2 from the first review)

Read, not probed (the window is a few ms wide, as J405 says). Every await in showTerminal that I listed before now has a check after it: the font catch, the clusters import, the mockup mount and its catch, the canvas imports, and the add-host catch. A late mockup or canvas is disposed, not leaked. The final catch now ignores errors after the session ended. This covers every path I named.

401 path: cannot loop

checkSession returns undefined only for a 401 (auth.ts:267). Anything else throws and keeps the "Try again" screen. So a network error does not sign the person out. For a 401, endSession bumps the generation and calls renderAuth. The sign-in screen starts no session check of its own. showTerminal is re-entered only by:

  • the person finishing a passkey sign-in,
  • the one welcome timer after first setup,
  • device-approval cancel.

Each of these runs once per user action. In the worst case (cookie never accepted), the person sees sign-in again after each attempt. That is a visible, user-paced result, not a loop. The startup path (main.ts:217) and the foreground check were already 401 → sign-in.

Palette ranking: deterministic and stable

rankByTitle is a stable two-way partition. Groups with a title match go first, and order inside each part is unchanged. There is no sort, and there is no timing or hash input, so the same rows and query always give the same list. With no match it returns the same array. Ranking runs only in renderPalette, from the input handler or refreshPalette. The arrow keys only change selected and re-render nothing, so arrowing never reorders. When a refresh does reorder, the selection follows the action id (preserveAction).

  • docs-palette.spec.ts is back to pressing Enter on the first hit, and passes.
  • palette-ranking.spec.ts passes at both viewports.
  • palette-rank.test.ts (4 unit cases) I read but did not run separately; quick runs the changed package's unit tests.

Runs

  • Specs on the head: sign-out, palette-ranking, docs-palette and motion-bound together: 27 passed, 0 failed (4.7 min, specs.log).
  • verify quick (VERIFY_QUICK_BASE=origin/dev): PASS, all 11 rows, rc=0 (quick2.log). My first run failed doc comments on diff and fixed test waits, because my untracked probe file sat in the worktree (same cause as J431's first run). After I moved it out, the rerun passed. The brief says reviewers should not run quick; I ran it because the task asked.
  • Not run: verify fast, Mac, root, a real server.

Findings (all P3)

  1. A refresh can still move rows under the cursor. If the docs index loads while the palette is open with a query (via refreshPalette), a title match can move the Docs group to the front. The selection follows the same action, so Enter hits the same row, but the row moves on screen. This is intended for late rows. I'd leave it unless the owner minds.
  2. motionSettled looks only at running animations. A paused animation, or one still pending at the first look, is skipped. The bound would miss an over-long animation caught in that state. Today's CSS (240 ms palette, 180 ms toasts) is inside the limit. motion-bound.spec.ts shows 150 ms passes, 600 ms fails and an endless one is ignored. Counting pending as well would close the hole.
  3. The 401 wording is a copy choice: "Your session ended. Sign in again to continue." It matches what the background check already shows. I have no objection.
  4. From the first review, unchanged: the D245 cache check looks at URLs only (P3-4). Not part of these follow-ups.

SHA reviewed: 59760ed59eca5d4e32fa0b3b2ba1ba569905fdcc.

## Review of `signout-followups-442` @ **59760ed59** (11 commits on origin/dev 547a48885) **Verdict: APPROVE.** I found no P0, P1 or P2. Four P3 notes follow; none blocks a merge. Evidence is on dev-02 in `~/r442b/logs/`: `specs.log`, `probes20.log`, `probesDE.log`, `quick2.log`. The tests ran on a production build through build-slot, from a detached worktree at 59760ed59. The probe spec is J431's `zz-review-probes.spec.ts`, never committed; I did not change it. ### Sign-out: no socket after sign-out Each probe runs at 1440×900 and at 393×852 with touch, and records every WebSocket created after the moment sign-out finished. | Probe | Runs | Sockets created after sign-out | Live at end | |---|---|---|---| | A: clusters mock, wasm held past sign-out, then released | 20 × 2 viewports | **0** in all 40 | 0 | | B: real cookie, product canvas, wasm held | 20 × 2 | **0** in all 40 | 0 | | C: connection dropped, sign-out during the reconnect backoff, 8 s wait | 20 × 2 | **0** in all 40 | 0 | | F: sign out right after the canvas opens, then check caches | 20 × 2 | **0** in all 40 | 0 | | D: OSC 52 in flight, racing and after sign-out | 3 × 2 | no clipboard writes, no toasts | 0 | | E: toast with a pending timer at sign-out | 3 × 2 | no toasts on the sign-in screen | 0 | 160 tests ran in 42.5 min (`probes20.log`, 160 passed). D and E: 12 passed (`probesDE.log`). Probe A is the one that showed 1 late socket on the desktop at b5a047adc (P2-1 in comment 88876). It is now 0 across 40 runs. The fix is the right one: `isCurrent` is asked at `terminal.ts` after the font, the wasm module and the `setTimeout(0)` turn, before `createRenderer` and `new TerminalClient`. The constructor opens the connection, so nothing is built for a dead session. The dispose at `main.ts` stays as a backstop and sets the marker `disposed`. The new spec requires the marker `cancelled`, so it would catch a regression to the backstop path. Its WebSocket Proxy counts constructor calls, so a refused handshake counts too. ### Generation guards (P3-2 from the first review) Read, not probed (the window is a few ms wide, as J405 says). Every `await` in `showTerminal` that I listed before now has a check after it: the font catch, the clusters import, the mockup mount and its catch, the canvas imports, and the add-host catch. A late mockup or canvas is disposed, not leaked. The final catch now ignores errors after the session ended. This covers every path I named. ### 401 path: cannot loop `checkSession` returns `undefined` only for a 401 (`auth.ts:267`). Anything else throws and keeps the "Try again" screen. So a network error does not sign the person out. For a 401, `endSession` bumps the generation and calls `renderAuth`. The sign-in screen starts no session check of its own. `showTerminal` is re-entered only by: - the person finishing a passkey sign-in, - the one welcome timer after first setup, - device-approval cancel. Each of these runs once per user action. In the worst case (cookie never accepted), the person sees sign-in again after each attempt. That is a visible, user-paced result, not a loop. The startup path (`main.ts:217`) and the foreground check were already 401 → sign-in. ### Palette ranking: deterministic and stable `rankByTitle` is a stable two-way partition. Groups with a title match go first, and order inside each part is unchanged. There is no sort, and there is no timing or hash input, so the same rows and query always give the same list. With no match it returns the same array. Ranking runs only in `renderPalette`, from the input handler or `refreshPalette`. The arrow keys only change `selected` and re-render nothing, so arrowing never reorders. When a refresh does reorder, the selection follows the action id (`preserveAction`). - `docs-palette.spec.ts` is back to pressing Enter on the first hit, and passes. - `palette-ranking.spec.ts` passes at both viewports. - `palette-rank.test.ts` (4 unit cases) I read but did not run separately; `quick` runs the changed package's unit tests. ### Runs - **Specs on the head:** sign-out, palette-ranking, docs-palette and motion-bound together: **27 passed, 0 failed** (4.7 min, `specs.log`). - **`verify quick`** (`VERIFY_QUICK_BASE=origin/dev`): **PASS**, all 11 rows, rc=0 (`quick2.log`). My first run failed `doc comments on diff` and `fixed test waits`, because my untracked probe file sat in the worktree (same cause as J431's first run). After I moved it out, the rerun passed. The brief says reviewers should not run `quick`; I ran it because the task asked. - Not run: `verify fast`, Mac, root, a real server. ### Findings (all P3) 1. **A refresh can still move rows under the cursor.** If the docs index loads while the palette is open with a query (via `refreshPalette`), a title match can move the Docs group to the front. The selection follows the same action, so Enter hits the same row, but the row moves on screen. This is intended for late rows. I'd leave it unless the owner minds. 2. **`motionSettled` looks only at `running` animations.** A paused animation, or one still `pending` at the first look, is skipped. The bound would miss an over-long animation caught in that state. Today's CSS (240 ms palette, 180 ms toasts) is inside the limit. `motion-bound.spec.ts` shows 150 ms passes, 600 ms fails and an endless one is ignored. Counting `pending` as well would close the hole. 3. **The 401 wording is a copy choice:** "Your session ended. Sign in again to continue." It matches what the background check already shows. I have no objection. 4. **From the first review, unchanged:** the D245 cache check looks at URLs only (P3-4). Not part of these follow-ups. SHA reviewed: `59760ed59eca5d4e32fa0b3b2ba1ba569905fdcc`.
Sign in to join this conversation.
No labels
launch-qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/infraternal#442
No description provided.