Sign-in: passkey button missing after cross-tab sign-out (authflash e2e) #1473

Closed
opened 2026-10-08 13:52:07 +00:00 by kayg · 12 comments
Owner

Problem

apps/web/e2e/authflash-850.mjs fails deterministically after the cross-tab sign-out step: the sign-in page's "Continue with a passkey" button never appears. Found by the #1459 job (worktree fix-1459, head d4d1670cf); the earlier steps (signed-out redirect, service-worker sign-out and expiry) pass.

Expected

After signing out in another tab, this tab shows the sign-in page with the passkey button within 2 s, and after signing in returns to the exact link. Determine whether this is a product bug (sign-in page not rendering after a cross-tab sign-out, e.g. stale service worker state or a blocked auth bootstrap) or a stale test, and fix the right one with evidence. Also fix the stale .ql-title h2 locator in apps/web/e2e/browser-soak.mjs.

## Problem `apps/web/e2e/authflash-850.mjs` fails deterministically after the cross-tab sign-out step: the sign-in page's "Continue with a passkey" button never appears. Found by the #1459 job (worktree fix-1459, head d4d1670cf); the earlier steps (signed-out redirect, service-worker sign-out and expiry) pass. ## Expected After signing out in another tab, this tab shows the sign-in page with the passkey button within 2 s, and after signing in returns to the exact link. Determine whether this is a product bug (sign-in page not rendering after a cross-tab sign-out, e.g. stale service worker state or a blocked auth bootstrap) or a stale test, and fix the right one with evidence. Also fix the stale `.ql-title h2` locator in apps/web/e2e/browser-soak.mjs.
Author
Owner

Starting authflash-1473 on job/authflash-1473, based on af202e1514 (origin/dev). I will reproduce the cross-tab sign-out flow, determine whether the missing passkey control is a product or test defect, and update the stale browser-soak title locator.

Starting authflash-1473 on job/authflash-1473, based on af202e1514955ddf0f8b4b3d2503c780d807ed84 (origin/dev). I will reproduce the cross-tab sign-out flow, determine whether the missing passkey control is a product or test defect, and update the stale browser-soak title locator.
Author
Owner

The first e2e run stopped before the cross-tab case. The real passkey return navigated to /n/<calternal-id>#verification, which is the Notes deep-link grammar in DESIGN §33 and matches the test target. assertRestored still waited for /notes/<id>, so it timed out on that valid return. This is a stale test expectation. I updated the helper to compare the returned Note URL with target.link; I will rerun the e2e to reach the cross-tab case.

The first e2e run stopped before the cross-tab case. The real passkey return navigated to `/n/<calternal-id>#verification`, which is the Notes deep-link grammar in DESIGN §33 and matches the test target. `assertRestored` still waited for `/notes/<id>`, so it timed out on that valid return. This is a stale test expectation. I updated the helper to compare the returned Note URL with `target.link`; I will rerun the e2e to reach the cross-tab case.
Author
Owner

After correcting the stale /notes/<id> test locator, the authflash run reached the test-only cached-shell cross-tab case. The other tab signed out, the original tab used the passkey API successfully (login/start and login/finish both returned 200), and the test continued to the next sign-out scenario only after checking the exact path, query and fragment. This does not reproduce a product auth-bootstrap or service-worker bug on current origin/dev; the failure here was a stale test route assertion. I will add the requested 2-second visibility check so the expected timing stays covered.

After correcting the stale `/notes/<id>` test locator, the authflash run reached the test-only cached-shell cross-tab case. The other tab signed out, the original tab used the passkey API successfully (`login/start` and `login/finish` both returned 200), and the test continued to the next sign-out scenario only after checking the exact path, query and fragment. This does not reproduce a product auth-bootstrap or service-worker bug on current `origin/dev`; the failure here was a stale test route assertion. I will add the requested 2-second visibility check so the expected timing stays covered.
Author
Owner

The authflash e2e next failed after the auth cases, in its existing public text-file preview check. A focused real-server reproduction showed /api/v1/public/authflash-public returns mime: text/plain, but Quick Look displayed “No preview for this kind of file” and did not request preview bytes. PublicLinkPage.singleKind uses the MIME, while singleItem() dropped it and passed mime: null to the shared viewer. I will pass the public MIME into that viewer item; this preserves the intended Preview action and lets the full e2e complete.

The authflash e2e next failed after the auth cases, in its existing public text-file preview check. A focused real-server reproduction showed `/api/v1/public/authflash-public` returns `mime: text/plain`, but Quick Look displayed “No preview for this kind of file” and did not request preview bytes. `PublicLinkPage.singleKind` uses the MIME, while `singleItem()` dropped it and passed `mime: null` to the shared viewer. I will pass the public MIME into that viewer item; this preserves the intended Preview action and lets the full e2e complete.
Author
Owner

The post-merge bun run check stopped at scripts/perf-lint --check because the exact cache.raw-read exception for PublicLinkPage.svelte had an old module hash. The live finding is still one raw fetch with the same fetch limit; I am updating that entry’s hash only. Svelte reported 0 errors and 4 warnings in two unrelated files.

The post-merge `bun run check` stopped at `scripts/perf-lint --check` because the exact `cache.raw-read` exception for `PublicLinkPage.svelte` had an old module hash. The live finding is still one raw `fetch` with the same `fetch` limit; I am updating that entry’s hash only. Svelte reported 0 errors and 4 warnings in two unrelated files.
Author
Owner

After refreshing the ledger hash, the next bun run check exposed the matching exact hash in contracts/perf/adoption-1058.json: perf-lint reports that the checkpoint differs from its live ledger entry. I will refresh that duplicate pin to the same parsed scope, with no change to the rule, limit, owner or expiry.

After refreshing the ledger hash, the next `bun run check` exposed the matching exact hash in `contracts/perf/adoption-1058.json`: perf-lint reports that the checkpoint differs from its live ledger entry. I will refresh that duplicate pin to the same parsed scope, with no change to the rule, limit, owner or expiry.
Author
Owner

The frontend check found stale exact performance hashes after preserving the file MIME in PublicLinkPage.svelte. The source parser reported six rendered list scopes in that file; their exact fingerprints include the component hash, so the edit changed all 72 scoped records in each of contracts/perf/exceptions.json and contracts/perf/adoption-1058.json. I refreshed those fingerprints while keeping rule names, bounds, owners, expiry dates and test references unchanged. The next frontend check will verify the ledgers against live source.

The frontend check found stale exact performance hashes after preserving the file MIME in `PublicLinkPage.svelte`. The source parser reported six rendered list scopes in that file; their exact fingerprints include the component hash, so the edit changed all 72 scoped records in each of `contracts/perf/exceptions.json` and `contracts/perf/adoption-1058.json`. I refreshed those fingerprints while keeping rule names, bounds, owners, expiry dates and test references unchanged. The next frontend check will verify the ledgers against live source.
Author
Owner

The current-build authflash run passed the cold Note, file and settings returns plus worker sign-out/expiry cases. It then loaded the cached document from the test worker, and the cross-tab case proceeded past the 2,000 ms visible passkey-button assertion: passkey start and finish returned 200, and the test awaited the exact path, query and fragment on return. The full process produced no further progress markers and was stopped at 25 minutes; it did not report a test failure. The browser, test server and runner exited during cleanup. I am isolating the later public-preview tail with a bounded probe.

The current-build authflash run passed the cold Note, file and settings returns plus worker sign-out/expiry cases. It then loaded the cached document from the test worker, and the cross-tab case proceeded past the 2,000 ms visible passkey-button assertion: passkey start and finish returned 200, and the test awaited the exact path, query and fragment on return. The full process produced no further progress markers and was stopped at 25 minutes; it did not report a test failure. The browser, test server and runner exited during cleanup. I am isolating the later public-preview tail with a bounded probe.
Author
Owner

Screenshot evidence

These are actual-size Playwright captures of the real public share and its Quick Look preview, with macOS platform emulation. The ZIP contains all 16 screenshots, including phone, tablet and desktop in light and dark. The paired phone and desktop images show the public page beside the opened preview.

### Screenshot evidence These are actual-size Playwright captures of the real public share and its Quick Look preview, with macOS platform emulation. The ZIP contains all 16 screenshots, including phone, tablet and desktop in light and dark. The paired phone and desktop images show the public page beside the opened preview. - [Full screenshot set (16 PNGs)](https://git.kayg.org/attachments/10b3c1bb-1570-463a-9ebe-3faaef6fe494) - [Light phone comparison](https://git.kayg.org/attachments/44ed4450-c9f3-4f72-aa23-06d62135a8a4) ![Light public share and preview at phone width](https://git.kayg.org/attachments/44ed4450-c9f3-4f72-aa23-06d62135a8a4) - [Dark phone comparison](https://git.kayg.org/attachments/4b3d82be-4c8d-49cd-8b3b-2768bc0a44e1) ![Dark public share and preview at phone width](https://git.kayg.org/attachments/4b3d82be-4c8d-49cd-8b3b-2768bc0a44e1) - [Light desktop comparison](https://git.kayg.org/attachments/1009375d-15c5-4eeb-a406-be422b070483) ![Light public share and preview at desktop width](https://git.kayg.org/attachments/1009375d-15c5-4eeb-a406-be422b070483) - [Dark desktop comparison](https://git.kayg.org/attachments/6de3b2ad-ef62-47b4-9c08-0ffc41d0c94b) ![Dark public share and preview at desktop width](https://git.kayg.org/attachments/6de3b2ad-ef62-47b4-9c08-0ffc41d0c94b)
Author
Owner

The public text-preview benchmark now completes in preview-only mode. It uses the shared release server locally (calternal-dev); load average was 15.15, 14.12 and 17.85, so treat these as observational numbers. docs/perf/baseline.json has no direct public text-preview baseline.

  • 16 KiB text preview, 50 requests: p50 48.0 ms, p95 55.9 ms, server CPU 0.19 s, peak RSS 211,968,000 bytes; all 50 returned 200.
  • 2 MiB text preview, burst of 16: p50 314.6 ms, p95 361.3 ms, server CPU 0.47 s, peak RSS 226,660,352 bytes; all 16 returned 200.

The full existing bench/public-links-755.mjs run stopped afterward at its pre-existing 32 MiB upload fixture: the API returned 413 request body too large where that benchmark expects 201. I did not change that expectation. PUBLIC_LINKS_PREVIEW_ONLY=1 skips only that unrelated large-original and password-storm tail while retaining the preview samples.

The public text-preview benchmark now completes in preview-only mode. It uses the shared release server locally (`calternal-dev`); load average was 15.15, 14.12 and 17.85, so treat these as observational numbers. `docs/perf/baseline.json` has no direct public text-preview baseline. - 16 KiB text preview, 50 requests: p50 48.0 ms, p95 55.9 ms, server CPU 0.19 s, peak RSS 211,968,000 bytes; all 50 returned 200. - 2 MiB text preview, burst of 16: p50 314.6 ms, p95 361.3 ms, server CPU 0.47 s, peak RSS 226,660,352 bytes; all 16 returned 200. The full existing `bench/public-links-755.mjs` run stopped afterward at its pre-existing 32 MiB upload fixture: the API returned 413 `request body too large` where that benchmark expects 201. I did not change that expectation. `PUBLIC_LINKS_PREVIEW_ONLY=1` skips only that unrelated large-original and password-storm tail while retaining the preview samples.
Author
Owner

Finished

Branch: job/authflash-1473
Head SHA: 43a24d930451ed94257b37fff67a518b787130c2

Built

  • Updated authflash to serve the worktree production build in the real-server e2e, assert that the passkey button is visible within 2 seconds after cross-tab sign-out, and verify the exact path, query and fragment on return.
  • Replaced the stale Note /notes/<id> expectation with the canonical /n/<calternal-id>#<block-id> route from DESIGN §33.
  • Fixed public text Quick Look by carrying the server MIME into the shared QuickLook item. The real preview now renders text through the existing shared TextView path.
  • Replaced the stale .ql-title h2 locator with the existing quickLookHeading() helper. Added bounded default waits and stage markers to authflash so a missing state does not leave the browser waiting indefinitely.
  • Extended bench/public-links-755.mjs with average and burst plain-text preview profiles.

Files

  • apps/web/e2e/authflash-850.mjs
  • apps/web/e2e/browser-soak.mjs
  • apps/web/src/lib/files/PublicLinkPage.svelte
  • bench/public-links-755.mjs
  • contracts/perf/exceptions.json
  • contracts/perf/adoption-1058.json

UX gaps closed

  • The sign-in page shows the passkey action within 2 seconds after sign-out in another tab. The end-to-end confirmed the exact deep link return and no private chrome on the cached shell.
  • Public text shares open the existing Quick Look preview and show the real file contents.
  • Captured the real public share beside its preview at 390, 820 and 1440 px in light and dark with macOS platform emulation. The full-size set and phone/desktop comparisons are attached in the preceding comment.
  • UX gaps left: none found.

Performance

The preview action uses one existing /preview request and one shared viewer render; this change adds no scan or extra request. There is no direct public text-preview baseline in docs/perf/baseline.json.

Local run on the shared release server (calternal-dev; load average 15.15, 14.12, 17.85):

  • 16 KiB text preview, 50 requests: p50 48.0 ms, p95 55.9 ms, CPU 0.19 s, peak RSS 211,968,000 bytes; 50/50 returned 200.
  • 2 MiB text preview, burst of 16: p50 314.6 ms, p95 361.3 ms, CPU 0.47 s, peak RSS 226,660,352 bytes; 16/16 returned 200.

The default public-links benchmark also reaches an older 32 MiB upload fixture that returns 413 request body too large where it expects 201. I did not change that expectation. PUBLIC_LINKS_PREVIEW_ONLY=1 runs the preview measurements without that unrelated tail.

Gates

bun run check:

perf-lint: PASS; 0 violations; 22544 scoped exceptions
svelte-check found 0 errors and 4 warnings in 2 files
bun_run_check_exit=0

The four warnings are the existing unused CSS selectors in MailView.svelte and the .ready selector in the money page.

bun run test:e2e:authflash-850 exited 0:

{"result":"passed","signedInWarmDeepLinkMs":367,"serverRedirectStatus":302,"serviceWorkerCachedShell":true}

The cross-tab marker was PASS authflash cached-shell cross-tab: sign-in restored exact deep link.

node --check passed for the changed e2e and benchmark scripts. cargo clean output:

Removed 1 file, 356B total

No Rust files changed, so Rust fmt/clippy/test were not run. The full Vitest suite was not run per the merge-round verification policy.

Decisions and known gaps

DESIGN §33 defines the Note link grammar; no product behavior decision was needed beyond following it. For test behavior, I reused routeCurrentBuild() and quickLookHeading(), kept the passkey readiness bound at 2 seconds, and set a 30-second default for other Playwright waits.

For the merge round, run cd apps/web && bun run test --maxWorkers=2 for the full web suite.

## Finished Branch: `job/authflash-1473` Head SHA: `43a24d930451ed94257b37fff67a518b787130c2` ### Built - Updated authflash to serve the worktree production build in the real-server e2e, assert that the passkey button is visible within 2 seconds after cross-tab sign-out, and verify the exact path, query and fragment on return. - Replaced the stale Note `/notes/<id>` expectation with the canonical `/n/<calternal-id>#<block-id>` route from DESIGN §33. - Fixed public text Quick Look by carrying the server MIME into the shared `QuickLook` item. The real preview now renders text through the existing shared `TextView` path. - Replaced the stale `.ql-title h2` locator with the existing `quickLookHeading()` helper. Added bounded default waits and stage markers to authflash so a missing state does not leave the browser waiting indefinitely. - Extended `bench/public-links-755.mjs` with average and burst plain-text preview profiles. ### Files - `apps/web/e2e/authflash-850.mjs` - `apps/web/e2e/browser-soak.mjs` - `apps/web/src/lib/files/PublicLinkPage.svelte` - `bench/public-links-755.mjs` - `contracts/perf/exceptions.json` - `contracts/perf/adoption-1058.json` ### UX gaps closed - The sign-in page shows the passkey action within 2 seconds after sign-out in another tab. The end-to-end confirmed the exact deep link return and no private chrome on the cached shell. - Public text shares open the existing Quick Look preview and show the real file contents. - Captured the real public share beside its preview at 390, 820 and 1440 px in light and dark with macOS platform emulation. The full-size set and phone/desktop comparisons are attached in the preceding comment. - UX gaps left: none found. ### Performance The preview action uses one existing `/preview` request and one shared viewer render; this change adds no scan or extra request. There is no direct public text-preview baseline in `docs/perf/baseline.json`. Local run on the shared release server (`calternal-dev`; load average 15.15, 14.12, 17.85): - 16 KiB text preview, 50 requests: p50 48.0 ms, p95 55.9 ms, CPU 0.19 s, peak RSS 211,968,000 bytes; 50/50 returned 200. - 2 MiB text preview, burst of 16: p50 314.6 ms, p95 361.3 ms, CPU 0.47 s, peak RSS 226,660,352 bytes; 16/16 returned 200. The default public-links benchmark also reaches an older 32 MiB upload fixture that returns 413 `request body too large` where it expects 201. I did not change that expectation. `PUBLIC_LINKS_PREVIEW_ONLY=1` runs the preview measurements without that unrelated tail. ### Gates `bun run check`: ```text perf-lint: PASS; 0 violations; 22544 scoped exceptions svelte-check found 0 errors and 4 warnings in 2 files bun_run_check_exit=0 ``` The four warnings are the existing unused CSS selectors in `MailView.svelte` and the `.ready` selector in the money page. `bun run test:e2e:authflash-850` exited 0: ```json {"result":"passed","signedInWarmDeepLinkMs":367,"serverRedirectStatus":302,"serviceWorkerCachedShell":true} ``` The cross-tab marker was `PASS authflash cached-shell cross-tab: sign-in restored exact deep link`. `node --check` passed for the changed e2e and benchmark scripts. `cargo clean` output: ```text Removed 1 file, 356B total ``` No Rust files changed, so Rust fmt/clippy/test were not run. The full Vitest suite was not run per the merge-round verification policy. ### Decisions and known gaps DESIGN §33 defines the Note link grammar; no product behavior decision was needed beyond following it. For test behavior, I reused `routeCurrentBuild()` and `quickLookHeading()`, kept the passkey readiness bound at 2 seconds, and set a 30-second default for other Playwright waits. For the merge round, run `cd apps/web && bun run test --maxWorkers=2` for the full web suite.
kayg referenced this issue from a commit 2026-10-08 19:43:32 +00:00
Author
Owner

Deployed to calternal.cloud in merge round 35b (build 9dc65437e, live 2026-10-09 ~11:07 IST). Closing.

Deployed to calternal.cloud in merge round 35b (build 9dc65437e, live 2026-10-09 ~11:07 IST). Closing.
kayg closed this issue 2026-10-09 05:36:36 +00:00
Commenting is not possible because the repository is archived.
No labels
No milestone
No project
No assignees
1 participant
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/calternal-v0#1473
No description provided.