UI: replace shadcn with calternal's design system (owner decision 2026-09-26) #46

Open
opened 2026-09-26 09:50:20 +00:00 by kayg · 411 comments
Owner

Owner decision (2026-09-26): remove shadcn-svelte completely ("i hate shadcn, please remove it completely. had the same circle in calternal too"). infraternal adopts calternal's own design system and components, copied as-is, with the same look.

This supersedes the 2026-09-24 decision to build on shadcn (#25).

The source is git.kayg.org/kayg/calternal, pinned at 6440a5f. It is read-only: observe and copy, never modify or push. The local reference clone at /home/kayg/ref/calternal has pushing disabled. Both repos are AGPL-3.0-only, so copying is allowed; the copied files keep their headers.

Plan:

  1. Inventory and port plan (docs/research/calternal-port.md).
  2. Port calternal's tokens, themes, materials, fonts, primitives and shell.
  3. Move every page onto them.
  4. Remove shadcn-svelte, bits-ui and every leftover.
  5. Visual comparison against calternal screenshots.
Owner decision (2026-09-26): **remove shadcn-svelte completely** ("i hate shadcn, please remove it completely. had the same circle in calternal too"). infraternal adopts **calternal's own design system and components**, copied as-is, with the same look. This supersedes the 2026-09-24 decision to build on shadcn (#25). The source is `git.kayg.org/kayg/calternal`, pinned at `6440a5f`. It is **read-only**: observe and copy, never modify or push. The local reference clone at `/home/kayg/ref/calternal` has pushing disabled. Both repos are AGPL-3.0-only, so copying is allowed; the copied files keep their headers. Plan: 1. Inventory and port plan (`docs/research/calternal-port.md`). 2. Port calternal's tokens, themes, materials, fonts, primitives and shell. 3. Move every page onto them. 4. Remove shadcn-svelte, bits-ui and every leftover. 5. Visual comparison against calternal screenshots.
Author
Owner

Starting inventory and port plan on branch calternal-port, base head 9d4876ae814fea4d0cf0c6b5d420fc33654ad726. I am keeping the reference clone /home/kayg/ref/calternal read-only; the only planned worktree edits are docs/research/calternal-port.md and the dated decision amendment. The graph index is absent for the reference clone, so I will inventory from its docs, exports and source paths without writing there.

Starting inventory and port plan on branch `calternal-port`, base head `9d4876ae814fea4d0cf0c6b5d420fc33654ad726`. I am keeping the reference clone `/home/kayg/ref/calternal` read-only; the only planned worktree edits are `docs/research/calternal-port.md` and the dated decision amendment. The graph index is absent for the reference clone, so I will inventory from its docs, exports and source paths without writing there.
Author
Owner

Pinned-source findings at calternal 6440a5f8382794f423847c07b98adfa4852a398d:

  • docs/DESIGN.md §8 and §34 describe reorderable navigation, but apps/web/src/lib/components/app-sidebar.svelte contains no reorder implementation. The vendored svelte-dnd-action is used in apps/web/src/routes/settings/appearance/AppearanceSection.svelte for the mode tray order; file move/drop is implemented in apps/web/src/lib/files/FilesBrowser.svelte and FilesSidebar.svelte. Keep infraternal's sidebar DnD as an explicit port requirement.
  • The mobile sidebar uses bits-ui Dialog headlessly in app-sidebar.svelte; the design system's menus, popovers, inspector and most sheet/dialog behavior are custom components. That is one dependency to replace when removing Bits UI.
  • The warm-tooltip behavior is implemented by calternal's own packages/ui/src/components/tooltip/{tip.ts,TooltipLayer.svelte,warmth.ts}. Its design notes say not to copy SvelteBits source because the upstream license is MIT + Commons Clause; the current upstream repository still reports that license: https://github.com/DavidHDev/svelte-bits/blob/main/LICENSE.md
Pinned-source findings at calternal `6440a5f8382794f423847c07b98adfa4852a398d`: - `docs/DESIGN.md` §8 and §34 describe reorderable navigation, but `apps/web/src/lib/components/app-sidebar.svelte` contains no reorder implementation. The vendored `svelte-dnd-action` is used in `apps/web/src/routes/settings/appearance/AppearanceSection.svelte` for the mode tray order; file move/drop is implemented in `apps/web/src/lib/files/FilesBrowser.svelte` and `FilesSidebar.svelte`. Keep infraternal's sidebar DnD as an explicit port requirement. - The mobile sidebar uses `bits-ui` Dialog headlessly in `app-sidebar.svelte`; the design system's menus, popovers, inspector and most sheet/dialog behavior are custom components. That is one dependency to replace when removing Bits UI. - The warm-tooltip behavior is implemented by calternal's own `packages/ui/src/components/tooltip/{tip.ts,TooltipLayer.svelte,warmth.ts}`. Its design notes say not to copy SvelteBits source because the upstream license is MIT + Commons Clause; the current upstream repository still reports that license: https://github.com/DavidHDev/svelte-bits/blob/main/LICENSE.md
Author
Owner

Completed the inventory, design-system decision amendment, mapping and port sequence in commit 4870b301b789840f6ae5d69d13756b9197f25d10 on calternal-port (not pushed). The source snapshot is /home/kayg/ref/calternal at 6440a5f8382794f423847c07b98adfa4852a398d; it remained clean. The temporary build copy and capture scratch directories were removed.

The report is docs/research/calternal-port.md. It covers the token/theme/font/glass system, package and app primitives with dependencies, confirmed UI rules, the sidebar DnD gap, visual targets, branch conflicts, exclusive port ownership, and the budgets that must remain in force. DECISIONS.md §24 supersedes the shadcn decisions in §§16 and 20. SvelteBits' MIT + Commons Clause license remains relevant; the source project's own tooltip implementation is used instead: https://github.com/DavidHDev/svelte-bits/blob/main/LICENSE.md

Reference-build findings worth carrying forward: the normal calternal layout sweep reported header recent 390 scale 1: div.fc-item "BURST_017.JPG": label centre above icon by 8.5px. The 390px share-dialog capture also shows the custom-link field extending beyond the right edge. Both findings are recorded in the report. The final capture-only run produced the requested screenshots; its output was checked 0 screens / LAYOUT SWEEP PASSED, which verifies capture completion only, not the source layout.

Surface mapping

Infraternal surface Calternal pattern or proposal
Shell ModeHeader, FloatingSidebar, SegmentedControl, PrimaryPill; one chrome row.
Sidebar with drag and drop No calternal navigation-reorder equivalent. Keep infraternal @dnd-kit, persistence, group/item operations, touch and keyboard support.
Account row No persistent bottom account row equivalent; place account action with the active chrome actions.
Inbox No equivalent actionable health/security inbox; use OverlaySurface/DialogChrome, list rows and StatusPill.
Dashboard cards Card, UIHeading, StatusPill, TagPill.
Hosts and containers No generic table; build semantic tokenized tables/lists and use Inspector for details.
Logs No live log viewer equivalent; keep the bounded, virtualized stream and mono font role.
Terminal No terminal emulator equivalent; keep the existing lazy terminal engine and rendering path.
Terminals tabs TabBar for session tabs.
Terminal splits No split-terminal component; preserve the target split tree and keyboard/drag resizing.
Confirmations DialogChrome, OverlaySurface, Pill actions and explicit destructive copy.
SSH trust flow No equivalent; use dialog/sheet chrome while preserving fingerprint and trust decisions.
Forms Native fields with shared tokens, focus ring, labels, validation and touch targets; no generic calternal Input/Select.
Toasts Calternal AppToaster/ToastBody pattern backed by svelte-sonner; adapt placement above the infraternal safe area.
Audit table No equivalent; keep a semantic bounded table and use Inspector for event detail.
Global search search-dialog.svelte + OverlaySurface; keep infraternal providers and authorization filtering.

Screenshot paths

All 20 PNGs are in /mnt/hdd/infraternal/artifacts/calternal-ref/. Desktop files are 1440×900; phone files are exactly 390×844.

  • Shell: shell-light-1440x900.png, shell-dark-1440x900.png, shell-light-390x844.png, shell-dark-390x844.png
  • Menu: menu-light-1440x900.png, menu-dark-1440x900.png, menu-light-390x844.png, menu-dark-390x844.png
  • Dialog: dialog-light-1440x900.png, dialog-dark-1440x900.png, dialog-light-390x844.png, dialog-dark-390x844.png
  • List: list-light-1440x900.png, list-dark-1440x900.png, list-light-390x844.png, list-dark-390x844.png
  • Settings: settings-light-1440x900.png, settings-dark-1440x900.png, settings-light-390x844.png, settings-dark-390x844.png

scripts/verify fast

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Completed the inventory, design-system decision amendment, mapping and port sequence in commit `4870b301b789840f6ae5d69d13756b9197f25d10` on `calternal-port` (not pushed). The source snapshot is `/home/kayg/ref/calternal` at `6440a5f8382794f423847c07b98adfa4852a398d`; it remained clean. The temporary build copy and capture scratch directories were removed. The report is `docs/research/calternal-port.md`. It covers the token/theme/font/glass system, package and app primitives with dependencies, confirmed UI rules, the sidebar DnD gap, visual targets, branch conflicts, exclusive port ownership, and the budgets that must remain in force. `DECISIONS.md` §24 supersedes the shadcn decisions in §§16 and 20. SvelteBits' MIT + Commons Clause license remains relevant; the source project's own tooltip implementation is used instead: https://github.com/DavidHDev/svelte-bits/blob/main/LICENSE.md Reference-build findings worth carrying forward: the normal calternal layout sweep reported `header recent 390 scale 1: div.fc-item "BURST_017.JPG": label centre above icon by 8.5px`. The 390px share-dialog capture also shows the custom-link field extending beyond the right edge. Both findings are recorded in the report. The final capture-only run produced the requested screenshots; its output was `checked 0 screens` / `LAYOUT SWEEP PASSED`, which verifies capture completion only, not the source layout. ### Surface mapping | Infraternal surface | Calternal pattern or proposal | |---|---| | Shell | `ModeHeader`, `FloatingSidebar`, `SegmentedControl`, `PrimaryPill`; one chrome row. | | Sidebar with drag and drop | No calternal navigation-reorder equivalent. Keep infraternal `@dnd-kit`, persistence, group/item operations, touch and keyboard support. | | Account row | No persistent bottom account row equivalent; place account action with the active chrome actions. | | Inbox | No equivalent actionable health/security inbox; use `OverlaySurface`/`DialogChrome`, list rows and `StatusPill`. | | Dashboard cards | `Card`, `UIHeading`, `StatusPill`, `TagPill`. | | Hosts and containers | No generic table; build semantic tokenized tables/lists and use `Inspector` for details. | | Logs | No live log viewer equivalent; keep the bounded, virtualized stream and mono font role. | | Terminal | No terminal emulator equivalent; keep the existing lazy terminal engine and rendering path. | | Terminals tabs | `TabBar` for session tabs. | | Terminal splits | No split-terminal component; preserve the target split tree and keyboard/drag resizing. | | Confirmations | `DialogChrome`, `OverlaySurface`, `Pill` actions and explicit destructive copy. | | SSH trust flow | No equivalent; use dialog/sheet chrome while preserving fingerprint and trust decisions. | | Forms | Native fields with shared tokens, focus ring, labels, validation and touch targets; no generic calternal Input/Select. | | Toasts | Calternal `AppToaster`/`ToastBody` pattern backed by `svelte-sonner`; adapt placement above the infraternal safe area. | | Audit table | No equivalent; keep a semantic bounded table and use `Inspector` for event detail. | | Global search | `search-dialog.svelte` + `OverlaySurface`; keep infraternal providers and authorization filtering. | ### Screenshot paths All 20 PNGs are in `/mnt/hdd/infraternal/artifacts/calternal-ref/`. Desktop files are 1440×900; phone files are exactly 390×844. - Shell: `shell-light-1440x900.png`, `shell-dark-1440x900.png`, `shell-light-390x844.png`, `shell-dark-390x844.png` - Menu: `menu-light-1440x900.png`, `menu-dark-1440x900.png`, `menu-light-390x844.png`, `menu-dark-390x844.png` - Dialog: `dialog-light-1440x900.png`, `dialog-dark-1440x900.png`, `dialog-light-390x844.png`, `dialog-dark-390x844.png` - List: `list-light-1440x900.png`, `list-dark-1440x900.png`, `list-light-390x844.png`, `list-dark-390x844.png` - Settings: `settings-light-1440x900.png`, `settings-dark-1440x900.png`, `settings-light-390x844.png`, `settings-dark-390x844.png` ### `scripts/verify fast` ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Starting Lane A foundation and Lane B shell/account/inbox work on branch calternal-port, base head 4870b301b789840f6ae5d69d13756b9197f25d10.

Starting Lane A foundation and Lane B shell/account/inbox work on branch `calternal-port`, base head `4870b301b789840f6ae5d69d13756b9197f25d10`.
Author
Owner

The pinned reference captures use the paper light mesh and midnight dark mesh; the shell's sidebar is a detached rounded card and mobile collapses to one title row. docs/contracts.md has no appearance preference endpoint, so Lane A will persist theme/background preferences per device and apply them before hydration; the server-backed sidebar order/group store remains untouched.

The pinned reference captures use the `paper` light mesh and `midnight` dark mesh; the shell's sidebar is a detached rounded card and mobile collapses to one title row. `docs/contracts.md` has no appearance preference endpoint, so Lane A will persist theme/background preferences per device and apply them before hydration; the server-backed sidebar order/group store remains untouched.
Author
Owner

Orchestrator, for port-ab: before finishing, merge origin/dev. It now has #44 (multi-tab refresh: auth.svelte.ts, api.ts, AppShell.svelte) and #37, and will soon have #36 (sidebar server persistence: lib/shell/navigation*.ts, Sidebar.svelte). Keep all of that behavior; lane B owns only the markup and styles.

Orchestrator, for port-ab: before finishing, merge `origin/dev`. It now has #44 (multi-tab refresh: `auth.svelte.ts`, `api.ts`, `AppShell.svelte`) and #37, and will soon have #36 (sidebar server persistence: `lib/shell/navigation*.ts`, `Sidebar.svelte`). Keep all of that behavior; lane B owns only the markup and styles.
Author
Owner

Lane A foundation and Lane B shell/account/inbox implementation are in commit eda4bba (Port calternal shell and appearance controls). The shell keeps SidebarInteractive.svelte's drag manager and persistence calls intact; search and inbox are lazy glass surfaces, and appearance stays per-device because the API contract has no appearance fields.

Package checks before the fast gate:

  • bun run --cwd packages/ui check: svelte-check found 0 errors and 0 warnings.
  • bun run --cwd packages/web check: svelte-check found 0 errors and 0 warnings.

scripts/verify fast output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

Next: update browser checks for the calternal header and FloatingSurface inbox, then capture and compare the required screenshots.

Lane A foundation and Lane B shell/account/inbox implementation are in commit `eda4bba` (`Port calternal shell and appearance controls`). The shell keeps `SidebarInteractive.svelte`'s drag manager and persistence calls intact; search and inbox are lazy glass surfaces, and appearance stays per-device because the API contract has no appearance fields. Package checks before the fast gate: - `bun run --cwd packages/ui check`: svelte-check found 0 errors and 0 warnings. - `bun run --cwd packages/web check`: svelte-check found 0 errors and 0 warnings. `scripts/verify fast` output: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` Next: update browser checks for the calternal header and FloatingSurface inbox, then capture and compare the required screenshots.
Author
Owner

Interaction findings kept in this lane:

  • The carried sidebar primitive still toggled on Ctrl+B, while calternal's copied shortcut registry advertises app.sidebar as the primary modifier plus backslash. SidebarState now uses the copied shared matcher, and Quick Search uses the same app.search registry entry shown by its tooltip.
  • On mobile, the icon-row close callback and its shell owner both changed openMobile; closing locally and then toggling in the owner reopened the sheet. The shell owner now performs the single state change.
  • The shared TooltipLayer needs the root data-input modality. The shell now tracks pointer and keyboard input using the copied modality predicate so keyboard focus can show the warm tooltip and visible focus ring.
Interaction findings kept in this lane: - The carried sidebar primitive still toggled on Ctrl+B, while calternal's copied shortcut registry advertises `app.sidebar` as the primary modifier plus backslash. `SidebarState` now uses the copied shared matcher, and Quick Search uses the same `app.search` registry entry shown by its tooltip. - On mobile, the icon-row close callback and its shell owner both changed `openMobile`; closing locally and then toggling in the owner reopened the sheet. The shell owner now performs the single state change. - The shared TooltipLayer needs the root `data-input` modality. The shell now tracks pointer and keyboard input using the copied modality predicate so keyboard focus can show the warm tooltip and visible focus ring.
Author
Owner

Lane B owner-rule cleanup is committed on calternal-port at a93f1b91eb7a1b0cb8ee1c25ae479a5d4e5bb48a.

Removed placeholder routes/pages for stacks, images, volumes, terminals, users & roles, AI agent tokens, infraternal agents, audit log and settings, plus the duplicate static /inbox page. Removed the Access/Admin placeholder groups and their navigation, the Settings account-menu action, dashboard CPU/memory/disk values and fake inbox count, the audit-log preview card, host-card telemetry placeholders, and the disabled “Open SSH terminal” control.

The inbox remains in the shell as a working glass panel. docs/contracts.md already defines GET /api/v1/inbox, PUT /api/v1/inbox/ssh-host-key/{host_id}/read, and POST /api/v1/hosts/{host_id}/ssh/host-key; the panel now loads those real items, marks them read, and confirms both fingerprints before trusting the observed new key. Browser checks now assert removed routes are unreachable and removed controls/links are absent; production browser verification is pending the shared gate slot.

Lane B owner-rule cleanup is committed on `calternal-port` at `a93f1b91eb7a1b0cb8ee1c25ae479a5d4e5bb48a`. Removed placeholder routes/pages for stacks, images, volumes, terminals, users & roles, AI agent tokens, infraternal agents, audit log and settings, plus the duplicate static `/inbox` page. Removed the Access/Admin placeholder groups and their navigation, the Settings account-menu action, dashboard CPU/memory/disk values and fake inbox count, the audit-log preview card, host-card telemetry placeholders, and the disabled “Open SSH terminal” control. The inbox remains in the shell as a working glass panel. `docs/contracts.md` already defines `GET /api/v1/inbox`, `PUT /api/v1/inbox/ssh-host-key/{host_id}/read`, and `POST /api/v1/hosts/{host_id}/ssh/host-key`; the panel now loads those real items, marks them read, and confirms both fingerprints before trusting the observed new key. Browser checks now assert removed routes are unreachable and removed controls/links are absent; production browser verification is pending the shared gate slot.
Author
Owner

Browser gate run 1 stopped in the terminal fixture before the app browser suite. The failing Ghostty case set generic data-theme="light"/"dark" values, which the copied palette does not define; the valid palettes are named (paper, noir). That left the terminal host token transparent while Ghostty retained its default gray canvas. I aligned the fixture with the named palettes and made its OS-scheme assertion match the per-device explicit palette behavior. Targeted verification: bun run test:browser --grep 'named palettes update terminal colors live' — 2 passed (xterm and Ghostty). The full browser gate will be rerun with INFRATERNAL_ARTIFACT_DIR set to the unique port-ab artifact directory.

Browser gate run 1 stopped in the terminal fixture before the app browser suite. The failing Ghostty case set generic `data-theme="light"`/`"dark"` values, which the copied palette does not define; the valid palettes are named (`paper`, `noir`). That left the terminal host token transparent while Ghostty retained its default gray canvas. I aligned the fixture with the named palettes and made its OS-scheme assertion match the per-device explicit palette behavior. Targeted verification: `bun run test:browser --grep 'named palettes update terminal colors live'` — 2 passed (xterm and Ghostty). The full browser gate will be rerun with `INFRATERNAL_ARTIFACT_DIR` set to the unique `port-ab` artifact directory.
Author
Owner

The corrected browser gate (artifacts scoped to /mnt/hdd/infraternal/artifacts/port-ab) passed Chromium setup, terminal fixture Playwright, web build and release binary build, then failed at passkey registration before route screenshots. waitForDashboard observed / with no headings; I am adding page runtime errors and an API health probe to the failure report before rerunning. The single curl connection-refused line may be the release-server startup health probe, so it is not evidence of a crash. No product-code cause is established yet.

The corrected browser gate (artifacts scoped to `/mnt/hdd/infraternal/artifacts/port-ab`) passed Chromium setup, terminal fixture Playwright, web build and release binary build, then failed at passkey registration before route screenshots. `waitForDashboard` observed `/` with no headings; I am adding page runtime errors and an API health probe to the failure report before rerunning. The single `curl` connection-refused line may be the release-server startup health probe, so it is not evidence of a crash. No product-code cause is established yet.
Author
Owner

Browser run 3 diagnostic evidence: the release server remained healthy (/api/health returned 200), while the client page error was Cannot read properties of undefined (reading 'isMobile'). AuthenticatedShell called Sidebar.useSidebar() from the same component that rendered Sidebar.Provider; the provider context was only available to descendants. Moved the context consumer into AuthenticatedShellBody.svelte, rendered under the provider. scripts/verify fast passed all steps after the fix; commit c4f1496. The full browser gate is being rerun next.

Browser run 3 diagnostic evidence: the release server remained healthy (`/api/health` returned 200), while the client page error was `Cannot read properties of undefined (reading 'isMobile')`. `AuthenticatedShell` called `Sidebar.useSidebar()` from the same component that rendered `Sidebar.Provider`; the provider context was only available to descendants. Moved the context consumer into `AuthenticatedShellBody.svelte`, rendered under the provider. `scripts/verify fast` passed all steps after the fix; commit `c4f1496`. The full browser gate is being rerun next.
Author
Owner

Browser run 4 reached the authenticated Containers route. The Stop action changed the unique browser container to Exited (137), but the browser assertion timed out waiting for its Stop … toast. The rebuilt authenticated shell no longer mounted a toaster; calternal mounts its app toaster once from the root layout, and this app's container actions still call toast.success/error. I am restoring the shared toaster at the shell level.

Browser run 4 reached the authenticated Containers route. The Stop action changed the unique browser container to `Exited (137)`, but the browser assertion timed out waiting for its `Stop …` toast. The rebuilt authenticated shell no longer mounted a toaster; calternal mounts its app toaster once from the root layout, and this app's container actions still call `toast.success/error`. I am restoring the shared toaster at the shell level.
Author
Owner

Browser run 5 passed the lifecycle action and toaster assertion, then failed at the Ghostty light terminal screenshot check. The failure showed empty --color-canvas/--color-text root tokens. The browser-check screenshot loop had removed data-theme to model the former generic system light/dark state; calternal tokens are defined only under named palettes. Updated the fixture to use Paper/Noir and matching mode classes while retaining OS color-scheme emulation. This keeps the terminal check against a supported app state.

Browser run 5 passed the lifecycle action and toaster assertion, then failed at the Ghostty light terminal screenshot check. The failure showed empty `--color-canvas`/`--color-text` root tokens. The browser-check screenshot loop had removed `data-theme` to model the former generic system light/dark state; calternal tokens are defined only under named palettes. Updated the fixture to use Paper/Noir and matching mode classes while retaining OS color-scheme emulation. This keeps the terminal check against a supported app state.
Author
Owner

Browser run 6 now passes the Ghostty Paper/Noir terminal color checks and both container Stop/Start toast assertions. The browser gate then measured METRIC initial route JS gzip: 147663 bytes and failed its 120 KiB (122880 byte) assertion. I am profiling the cold dashboard import graph and will split or defer shell code before the next browser run.

Browser run 6 now passes the Ghostty Paper/Noir terminal color checks and both container Stop/Start toast assertions. The browser gate then measured `METRIC initial route JS gzip: 147663 bytes` and failed its 120 KiB (122880 byte) assertion. I am profiling the cold dashboard import graph and will split or defer shell code before the next browser run.
Author
Owner

Browser run 7 confirmed that the sidebar DnD chunk is no longer in the fresh container-detail load: gzip fell from 238863 to 189063 bytes. The run stopped before the dashboard budget measurement when assertCleanPage saw a 1.19 CSS-pixel horizontal intersection between the pinned Container details title and a log marker after main-scroll restoration. This geometry check ran before the browser helper waited for the local UI fonts. I am making it wait for font readiness and one layout frame before checking text bounds; the overlap threshold remains unchanged.

Browser run 7 confirmed that the sidebar DnD chunk is no longer in the fresh container-detail load: gzip fell from 238863 to 189063 bytes. The run stopped before the dashboard budget measurement when `assertCleanPage` saw a 1.19 CSS-pixel horizontal intersection between the pinned `Container details` title and a log marker after main-scroll restoration. This geometry check ran before the browser helper waited for the local UI fonts. I am making it wait for font readiness and one layout frame before checking text bounds; the overlap threshold remains unchanged.
Author
Owner

Browser run 9 stopped in the terminal fixture: Playwright's default 127.0.0.1:4175 is already bound by an existing Node process. I left that listener untouched. packages/terminal/playwright.config.ts exposes INFRATERMINAL_TERMINAL_TEST_PORT; the next run will use a newly allocated per-run port.

Browser run 9 stopped in the terminal fixture: Playwright's default `127.0.0.1:4175` is already bound by an existing Node process. I left that listener untouched. `packages/terminal/playwright.config.ts` exposes `INFRATERMINAL_TERMINAL_TEST_PORT`; the next run will use a newly allocated per-run port.
Author
Owner

The same Container details/log-label collision reproduced after waiting for document.fonts.ready, so it was not a font race. Browser diagnostics show #main-content.scrollTop remained at 745 when navigation reached the container-detail route, which has no h1 to trigger the existing focus scroll. I am resetting the shell-owned scroller on route changes before the new route heading focus; the overlap check remains strict.

The same `Container details`/log-label collision reproduced after waiting for `document.fonts.ready`, so it was not a font race. Browser diagnostics show `#main-content.scrollTop` remained at 745 when navigation reached the container-detail route, which has no `h1` to trigger the existing focus scroll. I am resetting the shell-owned scroller on route changes before the new route heading focus; the overlap check remains strict.
Author
Owner

Orchestrator visual check of port-ab's light-1440x900-logs.png (22:40 IST); the review and page lanes must fix these:

  1. The "light" capture renders the dark theme. Check the theme selection in the browser harness.
  2. The sidebar header row is cramped: "INFRA…" is truncated next to "+ New group". It needs calternal's section-label pattern.
  3. There is an empty gap under the INFRASTRUCTURE heading.
  4. Container detail shows two titles: the serif "Container details ⌄" and a second large h1 with the container name. Use one title, per calternal.
  5. "Back to containers" floats alone on the right. Make it the title chevron menu or a breadcrumb inside the title, never a free-floating button.
Orchestrator visual check of port-ab's `light-1440x900-logs.png` (22:40 IST); the review and page lanes must fix these: 1. The "light" capture renders the dark theme. Check the theme selection in the browser harness. 2. The sidebar header row is cramped: "INFRA…" is truncated next to "+ New group". It needs calternal's section-label pattern. 3. There is an empty gap under the INFRASTRUCTURE heading. 4. Container detail shows **two** titles: the serif "Container details ⌄" and a second large h1 with the container name. Use one title, per calternal. 5. "Back to containers" floats alone on the right. Make it the title chevron menu or a breadcrumb inside the title, never a free-floating button.
Author
Owner

Run 11 at 3602de682c41a02826017a092a80b112576ee438 used a free terminal fixture port and passed the terminal fixture, release build, container actions, DATA/CREDIT accounting and Ghostty Paper/Noir color assertions. It confirms the remaining cold dashboard blocker: METRIC initial route JS gzip: 147687 bytes, 24807 bytes above the 120 KiB limit. The failure-only breakdown is in /tmp/port-ab-browser-run11.log; the lazy DnD chunk remains absent from the cold route.

Run 11 at `3602de682c41a02826017a092a80b112576ee438` used a free terminal fixture port and passed the terminal fixture, release build, container actions, DATA/CREDIT accounting and Ghostty Paper/Noir color assertions. It confirms the remaining cold dashboard blocker: `METRIC initial route JS gzip: 147687 bytes`, 24807 bytes above the 120 KiB limit. The failure-only breakdown is in `/tmp/port-ab-browser-run11.log`; the lazy DnD chunk remains absent from the cold route.
Author
Owner

At 9157c6bd0ab43e1ed5526311143f77e7a6385e51, the default sidebar no longer imports the shadcn Sheet or MenuButton wrappers on the cold route. The built breakdown showed chunks/DSWpLRjM.js at 20157 gzip bytes before the change; that chunk carried Bits UI sheet/dialog/tooltip code reachable from the static sidebar Root/MenuButton. The DnD sidebar remains on the existing interaction-triggered import, with its ordering/persistence callbacks untouched. The shell reserves a 247px floating card plus 61px to the display title to match the reference geometry.

scripts/verify fast output after this commit:
PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

At `9157c6bd0ab43e1ed5526311143f77e7a6385e51`, the default sidebar no longer imports the shadcn Sheet or MenuButton wrappers on the cold route. The built breakdown showed `chunks/DSWpLRjM.js` at 20157 gzip bytes before the change; that chunk carried Bits UI sheet/dialog/tooltip code reachable from the static sidebar Root/MenuButton. The DnD sidebar remains on the existing interaction-triggered import, with its ordering/persistence callbacks untouched. The shell reserves a 247px floating card plus 61px to the display title to match the reference geometry. `scripts/verify fast` output after this commit: PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest
Author
Owner

Correction to my prior chunk attribution: browser run 12 shows chunks/DSWpLRjM.js still loaded at 20157 gzip bytes after the cold Sidebar.Root/MenuButton path was removed. That change reduced the measured cold dashboard total by 630 bytes, from 147687 to 147057, and did not remove the shared chunk. My earlier comment overstated the attribution. I am tracing the remaining static shell dependency before changing it again. Run 12 otherwise passed the terminal fixture, release build, container actions, terminal DATA/CREDIT accounting and Ghostty Paper/Noir color checks; it failed only at the 120 KiB first-route budget assertion.

Correction to my prior chunk attribution: browser run 12 shows `chunks/DSWpLRjM.js` still loaded at 20157 gzip bytes after the cold `Sidebar.Root`/`MenuButton` path was removed. That change reduced the measured cold dashboard total by 630 bytes, from 147687 to 147057, and did not remove the shared chunk. My earlier comment overstated the attribution. I am tracing the remaining static shell dependency before changing it again. Run 12 otherwise passed the terminal fixture, release build, container actions, terminal DATA/CREDIT accounting and Ghostty Paper/Noir color checks; it failed only at the 120 KiB first-route budget assertion.
Author
Owner

At e9d6b5d3c1e851530f7a5e4cc8c2d26acdb093b2, the cold shell now imports the sidebar provider, inset, context and preview list wrappers by their component paths, avoiding ui/sidebar/index.ts. The barrel has 24 top-level component imports, including MenuButton, which imports Bits UI; run 12 showed that removing only the default Root/MenuButton render path left its 20157-byte shared chunk in the dashboard. Whether direct imports remove that chunk is pending the next browser run.

scripts/verify fast output after the direct-import change:
PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

At `e9d6b5d3c1e851530f7a5e4cc8c2d26acdb093b2`, the cold shell now imports the sidebar provider, inset, context and preview list wrappers by their component paths, avoiding `ui/sidebar/index.ts`. The barrel has 24 top-level component imports, including `MenuButton`, which imports Bits UI; run 12 showed that removing only the default Root/MenuButton render path left its 20157-byte shared chunk in the dashboard. Whether direct imports remove that chunk is pending the next browser run. `scripts/verify fast` output after the direct-import change: PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest
Author
Owner

Continuation head: 9298a38 (Import shell UI modules directly).

Browser run 13 (/tmp/port-ab-browser-run13.log) passed terminal setup, release build, container lifecycle/focus, terminal DATA/CREDIT accounting, and Ghostty Paper/Noir pixel checks. It stopped before screenshots at the first-route JavaScript budget assertion: METRIC initial route JS gzip: 131950 bytes against 122880. Run 12 measured 147057 bytes, so deferring the shared glass Menu removed 15107 bytes from the measured route; 9070 bytes remain over budget. The failing log includes the full per-chunk breakdown. No screenshots were captured in run 13 because the budget assertion precedes capture.

The shell now imports its four UI dependencies from individual source modules rather than the package-wide @infraternal/ui entry point. scripts/verify fast passed after this change:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

Next browser run will measure the direct imports. Artifacts remain under /mnt/hdd/infraternal/artifacts/port-ab/.

Continuation head: `9298a38` (`Import shell UI modules directly`). Browser run 13 (`/tmp/port-ab-browser-run13.log`) passed terminal setup, release build, container lifecycle/focus, terminal DATA/CREDIT accounting, and Ghostty Paper/Noir pixel checks. It stopped before screenshots at the first-route JavaScript budget assertion: `METRIC initial route JS gzip: 131950 bytes` against 122880. Run 12 measured 147057 bytes, so deferring the shared glass Menu removed 15107 bytes from the measured route; 9070 bytes remain over budget. The failing log includes the full per-chunk breakdown. No screenshots were captured in run 13 because the budget assertion precedes capture. The shell now imports its four UI dependencies from individual source modules rather than the package-wide `@infraternal/ui` entry point. `scripts/verify fast` passed after this change: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` Next browser run will measure the direct imports. Artifacts remain under `/mnt/hdd/infraternal/artifacts/port-ab/`.
Author
Owner

Head: a95822d (Avoid package root imports in cold shell).

Browser run 14 reproduced run 13 exactly: METRIC initial route JS gzip: 131950 bytes (budget: 122880). Container lifecycle/focus, terminal DATA/CREDIT accounting and Ghostty Paper/Noir pixel checks passed before the budget assertion. As with run 13, capture did not start because the assertion precedes screenshots. Log: /tmp/port-ab-browser-run14.log.

The first direct-import change removed the package root only from AuthenticatedShellBody.svelte; the measured build stayed identical because Sidebar.svelte and SidebarChrome.svelte still imported cold-shell items from that root. Commit a95822d removes those two remaining cold-shell package-root imports; the next browser run will measure that complete change.

scripts/verify fast passed after this change:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Head: `a95822d` (`Avoid package root imports in cold shell`). Browser run 14 reproduced run 13 exactly: `METRIC initial route JS gzip: 131950 bytes` (budget: 122880). Container lifecycle/focus, terminal DATA/CREDIT accounting and Ghostty Paper/Noir pixel checks passed before the budget assertion. As with run 13, capture did not start because the assertion precedes screenshots. Log: `/tmp/port-ab-browser-run14.log`. The first direct-import change removed the package root only from `AuthenticatedShellBody.svelte`; the measured build stayed identical because `Sidebar.svelte` and `SidebarChrome.svelte` still imported cold-shell items from that root. Commit `a95822d` removes those two remaining cold-shell package-root imports; the next browser run will measure that complete change. `scripts/verify fast` passed after this change: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Head: a95822d (Avoid package root imports in cold shell).

Browser run 15 (/tmp/port-ab-browser-run15.log) passed terminal setup, release build, container lifecycle/focus, terminal DATA/CREDIT accounting, and Ghostty Paper/Noir pixel checks. It stopped before screenshot capture at METRIC initial route JS gzip: 132452 bytes against 122880. The cold-route dependency layout changed, but measured transfer size did not improve; no screenshots were captured because the budget assertion precedes capture.

The largest measured chunk is chunks/BYRvys92.js at 24709 gzip bytes. The built chunk contains the twMerge symbol and is reached by the active dashboard/shell compatibility primitives. Those primitives import the class-merging helper, so the next experiment will remove merging from the cold-path-only class composition calls and use the installed variants package's lite implementation where those components have no conflicting utility classes. This must pass the fast and browser gates before acceptance.

Head: `a95822d` (`Avoid package root imports in cold shell`). Browser run 15 (`/tmp/port-ab-browser-run15.log`) passed terminal setup, release build, container lifecycle/focus, terminal DATA/CREDIT accounting, and Ghostty Paper/Noir pixel checks. It stopped before screenshot capture at `METRIC initial route JS gzip: 132452 bytes` against 122880. The cold-route dependency layout changed, but measured transfer size did not improve; no screenshots were captured because the budget assertion precedes capture. The largest measured chunk is `chunks/BYRvys92.js` at 24709 gzip bytes. The built chunk contains the `twMerge` symbol and is reached by the active dashboard/shell compatibility primitives. Those primitives import the class-merging helper, so the next experiment will remove merging from the cold-path-only class composition calls and use the installed variants package's lite implementation where those components have no conflicting utility classes. This must pass the fast and browser gates before acceptance.
Author
Owner

Run 16 reproduced the terminal prompt geometry failure before the initial-route gzip metric. The browser measured #main-content.scrollTop=745; the uncollapsed ModeHeader title ended at y=63.28 while the visible stderr badge began at y=61.66 (1.62px overlap). The DOM showed header.mode-header without its collapsed class. Root cause: ModeHeader's scroll handler recognized the window and large scrollers inside #route-content, but ignored the authenticated shell's primary #main-content scroller, which is outside #route-content.

Committed 7f5f512 (Collapse the header with shell scrolling): the primary shell scroller now drives header collapse, and the browser suite checks both collapse and expansion. scripts/verify fast passed all steps:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Run 16 reproduced the terminal prompt geometry failure before the initial-route gzip metric. The browser measured `#main-content.scrollTop=745`; the uncollapsed ModeHeader title ended at y=63.28 while the visible `stderr` badge began at y=61.66 (1.62px overlap). The DOM showed `header.mode-header` without its `collapsed` class. Root cause: ModeHeader's scroll handler recognized the window and large scrollers inside `#route-content`, but ignored the authenticated shell's primary `#main-content` scroller, which is outside `#route-content`. Committed `7f5f512` (`Collapse the header with shell scrolling`): the primary shell scroller now drives header collapse, and the browser suite checks both collapse and expansion. `scripts/verify fast` passed all steps: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Run 17 (fixture port 16853) validated the shell-header fix: the new scroll collapse/expand assertion passed, and the browser reported METRIC initial route JS gzip: 113279 bytes (budget: 122880). Terminal DATA/CREDIT and Ghostty Paper/Noir pixel checks also passed. The suite then stopped in checkKeyboardPaths because it looked for data-state on .app-sidebar[data-slot="sidebar-container"]. The rendered sidebar keeps state on its context root [data-slot="sidebar"][data-state]; the glass container is a child. Updated the browser selector in 2bc5a3b and reran scripts/verify fast, which passed every step (log /tmp/port-ab-fast-sidebar-selector.log). Browser gate is waiting because another worktree's browser gate and release build are active.

Run 17 (fixture port 16853) validated the shell-header fix: the new scroll collapse/expand assertion passed, and the browser reported `METRIC initial route JS gzip: 113279 bytes` (budget: 122880). Terminal DATA/CREDIT and Ghostty Paper/Noir pixel checks also passed. The suite then stopped in `checkKeyboardPaths` because it looked for `data-state` on `.app-sidebar[data-slot="sidebar-container"]`. The rendered sidebar keeps state on its context root `[data-slot="sidebar"][data-state]`; the glass container is a child. Updated the browser selector in `2bc5a3b` and reran `scripts/verify fast`, which passed every step (log `/tmp/port-ab-fast-sidebar-selector.log`). Browser gate is waiting because another worktree's browser gate and release build are active.
Author
Owner

Run 18 passed checkKeyboardPaths, the dashboard scroll checks and the first-route budget: METRIC initial route JS gzip: 113279 bytes. It reached the first inbox capture, where the material diagnostic measured blur blur(16px) saturate(1.5), the shared shadow and borderRadius: 0px. The zero radius was real: the copied FloatingSurface references --radius-menu / --radius-menu-touch, but the port's tokens omitted them. The read-only calternal theme-invariant values are 14px and 18px. The background-alpha diagnostic also returned null because its helper accepted only rgb()/rgba() while the glass tint is a color-mix() and Chromium serializes that as color(srgb … / alpha).

Committed ac249a8 (Restore floating menu corner tokens): added the two source values, updated docs/UI.md, made the browser helper read modern slash alpha, and asserted 14px pointer popover corners / 24px top corners for the bottom sheet. scripts/verify fast passed all steps:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

Run 18 has preliminary desktop-light captures at /mnt/hdd/infraternal/artifacts/port-ab/light-1440x900-dashboard.png, menu-open-light-1440x900.png, sidebar-rest-light-1440x900.png, sidebar-collapsed-light-1440x900.png, sidebar-hovered-light-1440x900.png, and account-row-light-1440x900.png. The suite stopped before inbox screenshot capture; more browser evidence is required.

Run 18 passed `checkKeyboardPaths`, the dashboard scroll checks and the first-route budget: `METRIC initial route JS gzip: 113279 bytes`. It reached the first inbox capture, where the material diagnostic measured blur `blur(16px) saturate(1.5)`, the shared shadow and `borderRadius: 0px`. The zero radius was real: the copied `FloatingSurface` references `--radius-menu` / `--radius-menu-touch`, but the port's tokens omitted them. The read-only calternal theme-invariant values are 14px and 18px. The background-alpha diagnostic also returned null because its helper accepted only `rgb()/rgba()` while the glass tint is a `color-mix()` and Chromium serializes that as `color(srgb … / alpha)`. Committed `ac249a8` (`Restore floating menu corner tokens`): added the two source values, updated `docs/UI.md`, made the browser helper read modern slash alpha, and asserted 14px pointer popover corners / 24px top corners for the bottom sheet. `scripts/verify fast` passed all steps: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` Run 18 has preliminary desktop-light captures at `/mnt/hdd/infraternal/artifacts/port-ab/light-1440x900-dashboard.png`, `menu-open-light-1440x900.png`, `sidebar-rest-light-1440x900.png`, `sidebar-collapsed-light-1440x900.png`, `sidebar-hovered-light-1440x900.png`, and `account-row-light-1440x900.png`. The suite stopped before inbox screenshot capture; more browser evidence is required.
Author
Owner

Run 19 confirmed the inbox radius and background-alpha fixes: the run passed dashboard scroll smoke, first-route gzip (METRIC initial route JS gzip: 113278 bytes), terminal accounting, Ghostty Paper/Noir pixels, and reached sidebar drag capture after capturing the desktop-light inbox. It then failed because createSidebarGroup returned a text-filter locator that matched both the active dragged group and dnd-kit’s hidden [data-dnd-placeholder] clone. The diagnostic showed the real group had data-dnd-dragging="true"; the drag itself had started. Updated the browser helper to exclude the hidden placeholder from the returned group locator. Fast and the next browser run will verify the selector change.

Desktop-light captures now include /mnt/hdd/infraternal/artifacts/port-ab/light-1440x900-dashboard.png, menu-open-light-1440x900.png, inbox-open-light-1440x900.png, sidebar-rest/collapsed/hovered, and account-row. Run 19 stopped before dark/mobile and mid-drag capture.

Run 19 confirmed the inbox radius and background-alpha fixes: the run passed dashboard scroll smoke, first-route gzip (`METRIC initial route JS gzip: 113278 bytes`), terminal accounting, Ghostty Paper/Noir pixels, and reached sidebar drag capture after capturing the desktop-light inbox. It then failed because `createSidebarGroup` returned a text-filter locator that matched both the active dragged group and dnd-kit’s hidden `[data-dnd-placeholder]` clone. The diagnostic showed the real group had `data-dnd-dragging="true"`; the drag itself had started. Updated the browser helper to exclude the hidden placeholder from the returned group locator. Fast and the next browser run will verify the selector change. Desktop-light captures now include `/mnt/hdd/infraternal/artifacts/port-ab/light-1440x900-dashboard.png`, `menu-open-light-1440x900.png`, `inbox-open-light-1440x900.png`, sidebar-rest/collapsed/hovered, and account-row. Run 19 stopped before dark/mobile and mid-drag capture.
Author
Owner

Orchestrator visual check at 01:40 IST (light-1440x900-hosts.png, inbox-open-light-1440x900.png). It is much closer to calternal: the gradient, glass card, icon pill, serif titles, and the glass inbox popover with backdrop blur. Remaining, for the port-ab review:

  1. Double title on every route. The serif chrome title ("Hosts ⌄") plus the page's own sans h1 ("Hosts"). Use one title, per calternal.
  2. The section labels are misaligned again: WORKSPACE at x≈39, INFRASTRUCTURE at x≈35. There is also an empty gap under INFRASTRUCTURE, probably an empty drop zone taking space at rest.
  3. The selected sidebar row hugs its text (Hosts, Dashboard). calternal's selected row spans the full sidebar width.
  4. The hosts table ENGINES column is blank. Either fill it or drop it (owner rule: nothing empty or unbuilt in the UI).
  5. The earlier findings (the light capture rendering dark, and the cramped header) look resolved in these captures. Confirm them in dark and at 390px.
Orchestrator visual check at 01:40 IST (`light-1440x900-hosts.png`, `inbox-open-light-1440x900.png`). It is much closer to calternal: the gradient, glass card, icon pill, serif titles, and the glass inbox popover with backdrop blur. Remaining, for the port-ab review: 1. **Double title on every route.** The serif chrome title ("Hosts ⌄") plus the page's own sans h1 ("Hosts"). Use one title, per calternal. 2. **The section labels are misaligned again:** WORKSPACE at x≈39, INFRASTRUCTURE at x≈35. There is also an empty gap under INFRASTRUCTURE, probably an empty drop zone taking space at rest. 3. **The selected sidebar row hugs its text** (Hosts, Dashboard). calternal's selected row spans the full sidebar width. 4. **The hosts table ENGINES column is blank.** Either fill it or drop it (owner rule: nothing empty or unbuilt in the UI). 5. The earlier findings (the light capture rendering dark, and the cramped header) look resolved in these captures. Confirm them in dark and at 390px.
Author
Owner

Follow-up to run 19: createSidebarGroup now returns a locator that excludes [data-dnd-placeholder], keeping the pointer-drag assertion attached to the real group while dnd-kit mounts its hidden clone. Committed as 27f39d7 (Exclude hidden DnD clones in browser checks). scripts/verify fast passed all steps; verbatim output is in /tmp/port-ab-fast-dnd-placeholder.log. The next browser run will verify the drag and continue dark/mobile captures.

Follow-up to run 19: `createSidebarGroup` now returns a locator that excludes `[data-dnd-placeholder]`, keeping the pointer-drag assertion attached to the real group while dnd-kit mounts its hidden clone. Committed as `27f39d7` (`Exclude hidden DnD clones in browser checks`). `scripts/verify fast` passed all steps; verbatim output is in `/tmp/port-ab-fast-dnd-placeholder.log`. The next browser run will verify the drag and continue dark/mobile captures.
Author
Owner

Run 20 passed through the pointer drag and captured /mnt/hdd/infraternal/artifacts/port-ab/sidebar-drag-light-1440x900.png. It failed only in cleanup because the check expected the temporary Access group to remain after “Reset arrangement”. navigation.svelte.ts::reset restores rootItems = [dashboardItem] and groups = initialGroups(), so deleting that temporary group is the intended behavior. The browser check now captures the default group order before creating Access and compares reset against that baseline.

Committed edd3bb9 (Check DnD reset against default groups). scripts/verify fast passed all steps; exact output is /tmp/port-ab-fast-reset-baseline.log. Run 20's earlier checks include METRIC initial route JS gzip: 113278 bytes, inbox material/radius, terminal DATA/CREDIT and Ghostty theme pixels. The next browser run will confirm reset cleanup and continue the dark/mobile captures.

Run 20 passed through the pointer drag and captured `/mnt/hdd/infraternal/artifacts/port-ab/sidebar-drag-light-1440x900.png`. It failed only in cleanup because the check expected the temporary `Access` group to remain after “Reset arrangement”. `navigation.svelte.ts::reset` restores `rootItems = [dashboardItem]` and `groups = initialGroups()`, so deleting that temporary group is the intended behavior. The browser check now captures the default group order before creating `Access` and compares reset against that baseline. Committed `edd3bb9` (`Check DnD reset against default groups`). `scripts/verify fast` passed all steps; exact output is `/tmp/port-ab-fast-reset-baseline.log`. Run 20's earlier checks include `METRIC initial route JS gzip: 113278 bytes`, inbox material/radius, terminal DATA/CREDIT and Ghostty theme pixels. The next browser run will confirm reset cleanup and continue the dark/mobile captures.
Author
Owner

Browser run 21 reached the application checks and measured METRIC initial route JS gzip: 113278 bytes. It stopped at the removed-route check because /stacks returned HTTP 200. The app uses adapter-static({ fallback: "index.html" }); SvelteKit's documented SPA fallback serves the app entry for unrecognized URLs, so the HTTP status is the fallback's status. The test now waits for the hydrated 404 view and its Not found: /stacks message to verify the removed page is unreachable. Browser run 21 output: /tmp/port-ab-browser-run21.log (exact full output will be retained in the run log on completion).

Browser run 21 reached the application checks and measured `METRIC initial route JS gzip: 113278 bytes`. It stopped at the removed-route check because `/stacks` returned HTTP 200. The app uses `adapter-static({ fallback: "index.html" })`; SvelteKit's documented SPA fallback serves the app entry for unrecognized URLs, so the HTTP status is the fallback's status. The test now waits for the hydrated 404 view and its `Not found: /stacks` message to verify the removed page is unreachable. Browser run 21 output: `/tmp/port-ab-browser-run21.log` (exact full output will be retained in the run log on completion).
Author
Owner

Light desktop comparison evidence: /mnt/hdd/infraternal/artifacts/port-ab/light-1440x900-dashboard.png showed the mode title duplicated by the page h1; Dashboard Refresh was below the mode header instead of in the top-right action pill; the sidebar added a sparkle dashboard link and grouped the panel-left toggle with Search/Inbox/Account. These mismatches are now addressed: the copied PageChrome contract registers Refresh in the shared action pill, route h1s remain available for heading navigation while the mode title is the visible title, and the sidebar puts Search/Inbox/Account at the left with the panel-left toggle at the right. The sparkle shortcut was removed because Dashboard is already a working navigation item. Fast gate output: see /tmp/port-ab-fast-shell-polish.log; commit 94fb0d4.

Light desktop comparison evidence: `/mnt/hdd/infraternal/artifacts/port-ab/light-1440x900-dashboard.png` showed the mode title duplicated by the page h1; Dashboard Refresh was below the mode header instead of in the top-right action pill; the sidebar added a sparkle dashboard link and grouped the panel-left toggle with Search/Inbox/Account. These mismatches are now addressed: the copied PageChrome contract registers Refresh in the shared action pill, route h1s remain available for heading navigation while the mode title is the visible title, and the sidebar puts Search/Inbox/Account at the left with the panel-left toggle at the right. The sparkle shortcut was removed because Dashboard is already a working navigation item. Fast gate output: see `/tmp/port-ab-fast-shell-polish.log`; commit `94fb0d4`.
Author
Owner

Browser run 22 confirmed the shell changes: first-route JavaScript measured 113556 bytes gzip (within 122880); the Dashboard Refresh header action, route-heading focus, and owned-route captures passed. The removed route check showed the SvelteKit client 404 as heading 404 / paragraph Not Found, so the assertion now checks that rendered response rather than a pathname-specific message. Full run output: /tmp/port-ab-browser-run22.log.

Browser run 22 confirmed the shell changes: first-route JavaScript measured `113556 bytes` gzip (within 122880); the Dashboard Refresh header action, route-heading focus, and owned-route captures passed. The removed route check showed the SvelteKit client 404 as `heading 404` / `paragraph Not Found`, so the assertion now checks that rendered response rather than a pathname-specific message. Full run output: `/tmp/port-ab-browser-run22.log`.
Author
Owner

Side-by-side difference recorded from run 22: /mnt/hdd/infraternal/artifacts/port-ab/light-1440x900-dashboard.png ended its dashboard card/action edge at x1420; matching /mnt/hdd/infraternal/artifacts/calternal-ref/shell-light-1440x900.png ends the content at x1382. Applied calternal's 4vw (capped at 60px) trailing padding to the mode header and route content, and switched the sidebar control to calternal's panel-left-close glyph. scripts/verify fast passed all steps; full output: /tmp/port-ab-fast-layout-align.log. Commit e1b298d. New browser capture will verify the alignment.

Side-by-side difference recorded from run 22: `/mnt/hdd/infraternal/artifacts/port-ab/light-1440x900-dashboard.png` ended its dashboard card/action edge at x1420; matching `/mnt/hdd/infraternal/artifacts/calternal-ref/shell-light-1440x900.png` ends the content at x1382. Applied calternal's 4vw (capped at 60px) trailing padding to the mode header and route content, and switched the sidebar control to calternal's `panel-left-close` glyph. `scripts/verify fast` passed all steps; full output: `/tmp/port-ab-fast-layout-align.log`. Commit `e1b298d`. New browser capture will verify the alignment.
Author
Owner

Run 22's /mnt/hdd/infraternal/artifacts/port-ab/sidebar-drag-light-1440x900.png showed the lazy DnD sidebar rendered the New group icon and label on separate lines. The style existed only in Sidebar.svelte's scoped CSS; the lazy interactive sidebar renders the header snippet through SidebarChrome, so it never received that rule. Moved the single rule to the shared slot owner and added a browser assertion for flex-row/nowrap behavior. scripts/verify fast passed all steps; output /tmp/port-ab-fast-shared-group-button.log. Commit b3a53b6.

Run 22's `/mnt/hdd/infraternal/artifacts/port-ab/sidebar-drag-light-1440x900.png` showed the lazy DnD sidebar rendered the New group icon and label on separate lines. The style existed only in `Sidebar.svelte`'s scoped CSS; the lazy interactive sidebar renders the header snippet through `SidebarChrome`, so it never received that rule. Moved the single rule to the shared slot owner and added a browser assertion for flex-row/nowrap behavior. `scripts/verify fast` passed all steps; output `/tmp/port-ab-fast-shared-group-button.log`. Commit `b3a53b6`.
Author
Owner

Browser run 23 reached the appearance flow after passing the 120 KiB first-route budget: METRIC initial route JS gzip: 113653 bytes. It failed because scripts/browser-check.mjs searched for the name Paper theme; the copied picker exposes the actual accessible name Paper White theme (packages/ui/src/themes.ts, matching the rendered account screenshot). Updated both light-theme locators to the actual name and committed as cb420f1. scripts/verify fast passed; a clean browser rerun is next.

Browser run 23 reached the appearance flow after passing the 120 KiB first-route budget: `METRIC initial route JS gzip: 113653 bytes`. It failed because `scripts/browser-check.mjs` searched for the name `Paper theme`; the copied picker exposes the actual accessible name `Paper White theme` (`packages/ui/src/themes.ts`, matching the rendered account screenshot). Updated both light-theme locators to the actual name and committed as `cb420f1`. `scripts/verify fast` passed; a clean browser rerun is next.
Author
Owner

Browser run 24 passed the appearance switch after the Paper White locator correction and captured the light desktop states. It measured METRIC initial route JS gzip: 113653 bytes. The final browser-error check then reported only SvelteKit console messages u: Not found: /stacks, /images, /volumes, /terminals, /users-roles, /ai-agent-tokens, /infraternal-agents, /audit-log, /settings and /inbox, emitted by the test's deliberate SPA 404 navigations after each 404 view was asserted. Added exact-path filtering scoped to those visits; all other console errors remain fatal. scripts/verify fast passed and the harness change is 94d4951. Next is a full browser rerun with a fresh fixture port.

Browser run 24 passed the appearance switch after the `Paper White` locator correction and captured the light desktop states. It measured `METRIC initial route JS gzip: 113653 bytes`. The final browser-error check then reported only SvelteKit console messages `u: Not found: /stacks`, `/images`, `/volumes`, `/terminals`, `/users-roles`, `/ai-agent-tokens`, `/infraternal-agents`, `/audit-log`, `/settings` and `/inbox`, emitted by the test's deliberate SPA 404 navigations after each 404 view was asserted. Added exact-path filtering scoped to those visits; all other console errors remain fatal. `scripts/verify fast` passed and the harness change is `94d4951`. Next is a full browser rerun with a fresh fixture port.
Author
Owner

Browser run 25 passed METRIC initial route JS gzip: 113653 bytes, the corrected appearance checks, and the intentional removed-route 404 checks. It then failed the medium-width DnD rail assertion with rail bounds x256–272 and .app-sidebar bounds x0–283. The floating surface itself is inset by its 18px gutter and ends at x265, so the rail center x264 is aligned to the visible glass edge within the 1px tolerance. Updated the browser assertion to measure [data-slot="sidebar-inner"] rather than the padded layout container. scripts/verify fast passed all checks; commit 7afdae6. Next is browser run 26 after the current sibling browser gate exits.

Browser run 25 passed `METRIC initial route JS gzip: 113653 bytes`, the corrected appearance checks, and the intentional removed-route 404 checks. It then failed the medium-width DnD rail assertion with rail bounds x256–272 and `.app-sidebar` bounds x0–283. The floating surface itself is inset by its 18px gutter and ends at x265, so the rail center x264 is aligned to the visible glass edge within the 1px tolerance. Updated the browser assertion to measure `[data-slot="sidebar-inner"]` rather than the padded layout container. `scripts/verify fast` passed all checks; commit `7afdae6`. Next is browser run 26 after the current sibling browser gate exits.
Author
Owner

Browser run 26 measured first-route JavaScript at 113653 bytes gzip and passed the corrected rail, appearance and removed-route checks. At 1024px, the shell leaves a 657px content column; the Containers filter grid kept viewport-based 801px/461px breakpoints, so its Refresh control extended to x1046 beyond the 1024px viewport. Updated only the existing filter layout to use named container-width queries on .containers-page; the filter contents and actions are unchanged. scripts/verify fast passed all checks; commit fe6fc74. Next is browser run 27 after the shared gate is clear.

Browser run 26 measured first-route JavaScript at `113653 bytes` gzip and passed the corrected rail, appearance and removed-route checks. At 1024px, the shell leaves a 657px content column; the Containers filter grid kept viewport-based 801px/461px breakpoints, so its Refresh control extended to x1046 beyond the 1024px viewport. Updated only the existing filter layout to use named container-width queries on `.containers-page`; the filter contents and actions are unchanged. `scripts/verify fast` passed all checks; commit `fe6fc74`. Next is browser run 27 after the shared gate is clear.
Author
Owner

Browser run 27 measured the initial route at 113652 bytes gzip, then failed the mobile drawer keyboard check after Escape because focus did not return to the “Show sidebar” opener. The opener and panel close control shared #chrome-sidebar-toggle; the close handler selected the first visible match while the sheet was closing. They now use explicit opener/panel targets, and focus follows the control that remains available after the transition. Fix committed as 23255e6a1f534f55464a93b1eb5cf7d1dc1d59f7.

scripts/verify fast output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Browser run 27 measured the initial route at 113652 bytes gzip, then failed the mobile drawer keyboard check after Escape because focus did not return to the “Show sidebar” opener. The opener and panel close control shared `#chrome-sidebar-toggle`; the close handler selected the first visible match while the sheet was closing. They now use explicit opener/panel targets, and focus follows the control that remains available after the transition. Fix committed as `23255e6a1f534f55464a93b1eb5cf7d1dc1d59f7`. `scripts/verify fast` output: ``` PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Browser run 28 still failed mobile focus return, showing the initial duplicate-ID fix was insufficient. Run 29's failure-only snapshot showed document.activeElement was BODY after the dialog detached, while the “Show sidebar” opener was connected, visible, and not inert; no modal remained. The sheet's Escape handling closes at the document level before the window handler, and Bits UI's saved focus restoration runs while the shell's background is still inert. The shell now handles Bits UI's onCloseAutoFocus, cancels that early restore, and focuses the opener on the next animation frame. It also keeps the fallback drawer's explicit Escape/backdrop return. Commit 62dbee583a3ae8c67f71ace22265982532aa7660 (with preceding control-target commit 23255e6a1f534f55464a93b1eb5cf7d1dc1d59f7).

Run 29 reached the focus check after measuring initial route JavaScript at 113707 bytes gzip. It failed only at mobile drawer focus return. A narrow diagnostic now records active element/inert state on that failure.

scripts/verify fast output after the change:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Browser run 28 still failed mobile focus return, showing the initial duplicate-ID fix was insufficient. Run 29's failure-only snapshot showed `document.activeElement` was `BODY` after the dialog detached, while the “Show sidebar” opener was connected, visible, and not inert; no modal remained. The sheet's Escape handling closes at the document level before the window handler, and Bits UI's saved focus restoration runs while the shell's background is still inert. The shell now handles Bits UI's `onCloseAutoFocus`, cancels that early restore, and focuses the opener on the next animation frame. It also keeps the fallback drawer's explicit Escape/backdrop return. Commit `62dbee583a3ae8c67f71ace22265982532aa7660` (with preceding control-target commit `23255e6a1f534f55464a93b1eb5cf7d1dc1d59f7`). Run 29 reached the focus check after measuring initial route JavaScript at `113707 bytes` gzip. It failed only at mobile drawer focus return. A narrow diagnostic now records active element/inert state on that failure. `scripts/verify fast` output after the change: ``` PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Browser run 30 measured the initial route at 113712 bytes gzip and passed the mobile drawer focus-return assertion after commit 62dbee5. It then failed in the required mobile touch reorder path: after Input.dispatchTouchEvent(touchStart), the DnD handle remained aria-pressed="false" for the 1-second activation wait, before any touch-move was sent. The run reached this check in the 320px drawer; desktop, medium-width, route cleanup, terminal accounting, and theme checks had passed.

Added a failure-only snapshot for received touchstart/pointerdown events, pointer type, hit target, touch-action, and handle geometry. Committed as 303952989271d619eb4d613703f52ff22bd4981f. The implementation remains unchanged pending that evidence. The gate uses Chromium's documented touch dispatch and viewport-relative CSS pixel coordinates: Input.dispatchTouchEvent, Emulation.setTouchEmulationEnabled.

scripts/verify fast after the diagnostic passed all steps:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Browser run 30 measured the initial route at `113712 bytes` gzip and passed the mobile drawer focus-return assertion after commit `62dbee5`. It then failed in the required mobile touch reorder path: after `Input.dispatchTouchEvent(touchStart)`, the DnD handle remained `aria-pressed="false"` for the 1-second activation wait, before any touch-move was sent. The run reached this check in the 320px drawer; desktop, medium-width, route cleanup, terminal accounting, and theme checks had passed. Added a failure-only snapshot for received `touchstart`/`pointerdown` events, pointer type, hit target, touch-action, and handle geometry. Committed as `303952989271d619eb4d613703f52ff22bd4981f`. The implementation remains unchanged pending that evidence. The gate uses Chromium's documented touch dispatch and viewport-relative CSS pixel coordinates: [Input.dispatchTouchEvent](https://chromedevtools.github.io/devtools-protocol/tot/Input/), [Emulation.setTouchEmulationEnabled](https://chromedevtools.github.io/devtools-protocol/tot/Emulation/). `scripts/verify fast` after the diagnostic passed all steps: ``` PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Starting C2 on branch port-c2, base head e12176d2781f38cee03d365977421e947a0b6a60.

I am mapping the terminal workspace port from #34 onto calternal primitives, checking the paged sessions API and the C1 ownership boundary, then will port the owned pages and run the required gates when clear.

Starting C2 on branch `port-c2`, base head `e12176d2781f38cee03d365977421e947a0b6a60`. I am mapping the terminal workspace port from #34 onto calternal primitives, checking the paged sessions API and the C1 ownership boundary, then will port the owned pages and run the required gates when clear.
Author
Owner

Starting C1 infrastructure pages on branch port-c1, base head e12176d2781f38cee03d365977421e947a0b6a60. I’m reading the port mapping and auditing the owned routes before making presentation changes. I’ll preserve API and action behavior, run the requested gates in the scheduling order, and attach screenshot paths and the calternal difference list when finished.

Starting C1 infrastructure pages on branch `port-c1`, base head `e12176d2781f38cee03d365977421e947a0b6a60`. I’m reading the port mapping and auditing the owned routes before making presentation changes. I’ll preserve API and action behavior, run the requested gates in the scheduling order, and attach screenshot paths and the calternal difference list when finished.
Author
Owner

Starting settings port on branch port-c3, based at e12176d2781f38cee03d365977421e947a0b6a60. Scope: owned settings and account routes only; using calternal snapshot 6440a5f8382794f423847c07b98adfa4852a398d read-only and lane A primitives/theme state. I’ll run scripts/verify fast and the browser gate when the shared load and gate conditions permit.

Starting settings port on branch `port-c3`, based at `e12176d2781f38cee03d365977421e947a0b6a60`. Scope: owned settings and account routes only; using calternal snapshot `6440a5f8382794f423847c07b98adfa4852a398d` read-only and lane A primitives/theme state. I’ll run `scripts/verify fast` and the browser gate when the shared load and gate conditions permit.
Author
Owner

C1 owns packages/web/src/routes/hosts/**, so I am assigning the SSH host-key review/trust dialog (shown fingerprint, explicit trust action, changed key blocked) to the host detail page. C2 will preserve the terminal's host-key failure as an honest, recoverable session error and will not add trust controls to the terminal. C1 can confirm this boundary here if their current implementation plan differs.

C1 owns `packages/web/src/routes/hosts/**`, so I am assigning the SSH host-key review/trust dialog (shown fingerprint, explicit trust action, changed key blocked) to the host detail page. C2 will preserve the terminal's host-key failure as an honest, recoverable session error and will not add trust controls to the terminal. C1 can confirm this boundary here if their current implementation plan differs.
Author
Owner

Finding: at base e12176d2781f38cee03d365977421e947a0b6a60, packages/web/src/routes/settings/** is absent and /settings is listed as removed in the browser check. The only working appearance controls are currently mixed into /account; lib/appearance/preferences.svelte.ts supports a local palette, its theme gradient, and a custom solid color. I’m moving those controls to /settings, retaining only profile fields on /account, and using usePageChrome for the shell title/menu. I will not add system mode, image upload, or remote background choices because the lane A state does not implement them.

Finding: at base `e12176d2781f38cee03d365977421e947a0b6a60`, `packages/web/src/routes/settings/**` is absent and `/settings` is listed as removed in the browser check. The only working appearance controls are currently mixed into `/account`; `lib/appearance/preferences.svelte.ts` supports a local palette, its theme gradient, and a custom solid color. I’m moving those controls to `/settings`, retaining only profile fields on `/account`, and using `usePageChrome` for the shell title/menu. I will not add system mode, image upload, or remote background choices because the lane A state does not implement them.
Author
Owner

Browser run 32 again measured first-route JavaScript at 113712 bytes gzip and passed the mobile drawer focus-return check. The mobile touch sequence reports a trusted pointerdown on the reorder button with pointerType=touch, button=0, buttons=1, isPrimary=true, maxTouchPoints=1, coarse pointer media, and touch-action:none. No pointermove/up/cancel was recorded, and aria-pressed stayed false for 1 second after touchStart. This narrows the failure to sensor acceptance or pointer capture rather than CDP delivering input to the wrong element.

The failure snapshot now includes the sensor marker, preventDefault state, and pointer-capture state. Commit 4c13171ff3d40b23ed4916154ba9f5457c0d636a. Run 32 stopped at the same first mobile touch drag check; visual captures past the mobile DnD path are still pending.

scripts/verify fast output after the diagnostic:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Browser run 32 again measured first-route JavaScript at `113712 bytes` gzip and passed the mobile drawer focus-return check. The mobile touch sequence reports a trusted `pointerdown` on the reorder button with `pointerType=touch`, `button=0`, `buttons=1`, `isPrimary=true`, `maxTouchPoints=1`, coarse pointer media, and `touch-action:none`. No pointermove/up/cancel was recorded, and `aria-pressed` stayed false for 1 second after touchStart. This narrows the failure to sensor acceptance or pointer capture rather than CDP delivering input to the wrong element. The failure snapshot now includes the sensor marker, preventDefault state, and pointer-capture state. Commit `4c13171ff3d40b23ed4916154ba9f5457c0d636a`. Run 32 stopped at the same first mobile touch drag check; visual captures past the mobile DnD path are still pending. `scripts/verify fast` output after the diagnostic: ``` PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

API scope finding from generated OpenAPI (packages/api-client/src/schema.ts): there are no /api/v1/users or /api/v1/roles operations, and no GET /api/v1/agents inventory operation. Agent operations are join-token create, enroll, certificate rotate and DELETE by id; without an inventory endpoint the UI cannot show or manage existing infraternal agents. Those two routes and the infraternal agents route will remain absent under the owner rule.

AI agent token management has GET /api/v1/tokens, POST /api/v1/tokens and DELETE /api/v1/tokens/{token_id}. The server has matching list/mint handlers in crates/server/src/auth.rs; I will port the list, scoped mint and revoke flow and only reveal the returned credentials at issuance.

API scope finding from generated OpenAPI (`packages/api-client/src/schema.ts`): there are no `/api/v1/users` or `/api/v1/roles` operations, and no `GET /api/v1/agents` inventory operation. Agent operations are join-token create, enroll, certificate rotate and DELETE by id; without an inventory endpoint the UI cannot show or manage existing infraternal agents. Those two routes and the infraternal agents route will remain absent under the owner rule. AI agent token management has `GET /api/v1/tokens`, `POST /api/v1/tokens` and `DELETE /api/v1/tokens/{token_id}`. The server has matching list/mint handlers in `crates/server/src/auth.rs`; I will port the list, scoped mint and revoke flow and only reveal the returned credentials at issuance.
Author
Owner

Navigation boundary finding: the calternal shell's navigation.svelte.ts currently has only Dashboard, Hosts and Containers. Once C2 restores /terminals and the token API supports /ai-agent-tokens, the user-facing features would be unreachable from the sidebar unless the shell owner re-adds their links. C2 will not edit the shell as instructed; please add these links from the shell lane after their route flows are in place, and retain no Users & roles or infraternal agents links.

Navigation boundary finding: the calternal shell's `navigation.svelte.ts` currently has only Dashboard, Hosts and Containers. Once C2 restores `/terminals` and the token API supports `/ai-agent-tokens`, the user-facing features would be unreachable from the sidebar unless the shell owner re-adds their links. C2 will not edit the shell as instructed; please add these links from the shell lane after their route flows are in place, and retain no Users & roles or infraternal agents links.
Author
Owner

Evidence and route decision: containers/+page.svelte still uses @ui/components/ui/* shadcn controls and stores __all in the three filters; packages/ui/src/lib/components/VirtualTable.svelte is also the legacy shadcn table wrapper. Lane A exports no generic table. C1 will add one route-local virtualized infrastructure list for Hosts and Containers, styled as calternal's full-width rows and using shared column tracks for header/cells. This keeps TanStack virtualization, keyboard row navigation, sorting, action focus restoration, and the live inventory API behavior without editing lane A or dependencies. The Dashboard currently has only live host/container/engine counts and attention rows; it contains no CPU/Memory/Disk placeholders or recent-activity card to delete.

Evidence and route decision: `containers/+page.svelte` still uses `@ui/components/ui/*` shadcn controls and stores `__all` in the three filters; `packages/ui/src/lib/components/VirtualTable.svelte` is also the legacy shadcn table wrapper. Lane A exports no generic table. C1 will add one route-local virtualized infrastructure list for Hosts and Containers, styled as calternal's full-width rows and using shared column tracks for header/cells. This keeps TanStack virtualization, keyboard row navigation, sorting, action focus restoration, and the live inventory API behavior without editing lane A or dependencies. The Dashboard currently has only live host/container/engine counts and attention rows; it contains no CPU/Memory/Disk placeholders or recent-activity card to delete.
Author
Owner

Accessibility coordination: AuthenticatedShellBody.svelte currently passes semanticHeading={false} to ModeHeader, which suppresses its shell-owned <h1>. The C2 page contract explicitly forbids route-owned h1/title blocks, so a route cannot restore heading navigation without violating the design contract. Please enable the ModeHeader semantic heading for these shell-titled pages while adding the functional route links noted above; C2 will keep its content headings at h2 and below.

Accessibility coordination: `AuthenticatedShellBody.svelte` currently passes `semanticHeading={false}` to `ModeHeader`, which suppresses its shell-owned `<h1>`. The C2 page contract explicitly forbids route-owned h1/title blocks, so a route cannot restore heading navigation without violating the design contract. Please enable the ModeHeader semantic heading for these shell-titled pages while adding the functional route links noted above; C2 will keep its content headings at h2 and below.
Author
Owner

Browser run 33 measured first-route JavaScript at 113712 bytes gzip and passed authenticated setup, initial route, terminal/theme smoke checks. It then timed out in setContainerSearch after 30 seconds without seeing the expected /api/v1/containers?text=<browser fixture> response. This occurred on the first container-list search after navigating to /containers, before the responsive shell or mobile touch checks.

Added failure-only request, response, request-failure, and input-state diagnostics to identify whether the filter emitted a different query, received a non-200 response, or emitted no request. Commit 02a5427302d091240ed6b59b20ace2e0023b6264.

scripts/verify fast passed all 16 steps:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Browser run 33 measured first-route JavaScript at `113712 bytes` gzip and passed authenticated setup, initial route, terminal/theme smoke checks. It then timed out in `setContainerSearch` after 30 seconds without seeing the expected `/api/v1/containers?text=<browser fixture>` response. This occurred on the first container-list search after navigating to `/containers`, before the responsive shell or mobile touch checks. Added failure-only request, response, request-failure, and input-state diagnostics to identify whether the filter emitted a different query, received a non-200 response, or emitted no request. Commit `02a5427302d091240ed6b59b20ace2e0023b6264`. `scripts/verify fast` passed all 16 steps: ``` PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Fast gate found one undeclared dependency in the first route-local infrastructure list attempt. scripts/verify fast reported:

FAIL fast: workspace package dependencies
Workspace package imports missing manifest declarations:
  packages/web/src/routes/containers/lib/InfrastructureList.svelte: @tanstack/svelte-virtual (missing @tanstack/svelte-virtual in packages/web/package.json)

The web manifest is outside C1 ownership and must stay unchanged, so the list now uses a fixed-height route-local window with a ResizeObserver and scroll-frame coalescing. Its header and row cells share one grid template; only the visible row window is mounted.

Fast gate found one undeclared dependency in the first route-local infrastructure list attempt. `scripts/verify fast` reported: ``` FAIL fast: workspace package dependencies Workspace package imports missing manifest declarations: packages/web/src/routes/containers/lib/InfrastructureList.svelte: @tanstack/svelte-virtual (missing @tanstack/svelte-virtual in packages/web/package.json) ``` The web manifest is outside C1 ownership and must stay unchanged, so the list now uses a fixed-height route-local window with a ResizeObserver and scroll-frame coalescing. Its header and row cells share one grid template; only the visible row window is mounted.
Author
Owner

Browser run 34 reached the final mobile DnD case: moving Containers into the new Access group. The earlier touch reorder, restore, and group reorder passed. On this fourth touch, the handle received a trusted primary touch pointer; @dnd-kit/dom@0.5.0 accepted the sensor and captured the pointer on document.body, but the handle remained aria-pressed=false before the helper sent its first move. Run log: /tmp/port-ab-browser-run34.log.

I added failure-only capture of the manager operation status and source/handle identity to distinguish a renderer transition from a stale or mismatched sortable entity. Commit: 8034267 (Diagnose mobile touch DnD lifecycle).

Fresh fast gate output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

Full log: /tmp/port-ab-fast-touch-manager-state.log.

The next browser replay is waiting for the unrelated integration gate in /home/kayg/wt/stacks-images to exit. Load5 is below 8, but pgrep -af 'scripts/verify' still shows that integration run.

Browser run 34 reached the final mobile DnD case: moving Containers into the new Access group. The earlier touch reorder, restore, and group reorder passed. On this fourth touch, the handle received a trusted primary touch pointer; `@dnd-kit/dom@0.5.0` accepted the sensor and captured the pointer on `document.body`, but the handle remained `aria-pressed=false` before the helper sent its first move. Run log: `/tmp/port-ab-browser-run34.log`. I added failure-only capture of the manager operation status and source/handle identity to distinguish a renderer transition from a stale or mismatched sortable entity. Commit: `8034267` (`Diagnose mobile touch DnD lifecycle`). Fresh fast gate output: ``` PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` Full log: `/tmp/port-ab-fast-touch-manager-state.log`. The next browser replay is waiting for the unrelated integration gate in `/home/kayg/wt/stacks-images` to exit. Load5 is below 8, but `pgrep -af 'scripts/verify'` still shows that integration run.
Author
Owner

C2 API route decision: the generated OpenAPI exposes GET/POST /api/v1/tokens and DELETE /api/v1/tokens/{token_id}. Mint may return either fresh secrets or a durable CredentialReplayResponse containing only already_issued, expires_in, and token_id; the page shows secrets only for the fresh response and explains the replay case without implying the secret can be recovered. The scope picker omits users:manage and roles:manage because the OpenAPI has no corresponding user or role operations. The agents:enroll and agents:revoke scopes remain selectable because the API does expose join-token, enrollment, and revoke operations; no agent inventory page is being added.

C2 API route decision: the generated OpenAPI exposes GET/POST `/api/v1/tokens` and DELETE `/api/v1/tokens/{token_id}`. Mint may return either fresh secrets or a durable `CredentialReplayResponse` containing only `already_issued`, `expires_in`, and `token_id`; the page shows secrets only for the fresh response and explains the replay case without implying the secret can be recovered. The scope picker omits `users:manage` and `roles:manage` because the OpenAPI has no corresponding user or role operations. The `agents:enroll` and `agents:revoke` scopes remain selectable because the API does expose join-token, enrollment, and revoke operations; no agent inventory page is being added.
Author
Owner

C2 integration dependency found while porting #34: the pages-shadcn stream client changes in packages/stream/src/index.ts are required for the requested terminal behavior, but that directory is outside this lane's owned files. On this base, OpenResult omits replay_start, parseOpenOk discards it, and persistent result validation does not require it; the OPEN_ERR validator also rejects the structured host_key_mismatch fingerprints. The route therefore cannot resume from the server's replay cursor or provide the reviewed host-detail error link until those reviewed #34 client changes are integrated. I will keep the route dependent on replay_start and won't substitute output_offset, which would skip retained output.

C2 integration dependency found while porting #34: the `pages-shadcn` stream client changes in `packages/stream/src/index.ts` are required for the requested terminal behavior, but that directory is outside this lane's owned files. On this base, `OpenResult` omits `replay_start`, `parseOpenOk` discards it, and persistent result validation does not require it; the OPEN_ERR validator also rejects the structured `host_key_mismatch` fingerprints. The route therefore cannot resume from the server's replay cursor or provide the reviewed host-detail error link until those reviewed #34 client changes are integrated. I will keep the route dependent on `replay_start` and won't substitute `output_offset`, which would skip retained output.
Author
Owner

The second scripts/verify fast run passed the web build and Clippy, then failed in an unchanged engine test:

test logs::tests::steady_state_framing_does_not_allocate_per_chunk ... FAILED
log framing allocated per chunk after warmup: Stats { allocations: 190, deallocations: 115, reallocations: 97, bytes_allocated: 151796, bytes_deallocated: 213828, bytes_reallocated: 8554 }

The failure is in crates/engine/src/logs.rs:349, outside C1’s owned files. I will rerun the fast gate after shared verification load clears to determine whether it reproduces.

The second `scripts/verify fast` run passed the web build and Clippy, then failed in an unchanged engine test: ``` test logs::tests::steady_state_framing_does_not_allocate_per_chunk ... FAILED log framing allocated per chunk after warmup: Stats { allocations: 190, deallocations: 115, reallocations: 97, bytes_allocated: 151796, bytes_deallocated: 213828, bytes_reallocated: 8554 } ``` The failure is in `crates/engine/src/logs.rs:349`, outside C1’s owned files. I will rerun the fast gate after shared verification load clears to determine whether it reproduces.
Author
Owner

Side-by-side review of /mnt/hdd/infraternal/artifacts/calternal-ref/shell-light-1440x900.png and /mnt/hdd/infraternal/artifacts/port-ab/sidebar-drag-light-1440x900.png found the navigation rows were fixed at 38px, used a heavier accent-colored selected label, and had a 2px group-row gap. Calternal uses its responsive --sidebar-row-h (32px base scaled on fine pointers, 44px on touch), a 4px scaled list gap, a lighter 11% accent selection fill with ink text, and title-case section labels.

Commit 39bdbfc moves the shared row recipe to SidebarChrome so the preview and lazy sortable rows use the same styles; the group rows now use --list-row-gap and section headings match calternal's weight, tracking and case. DnD/persistence callbacks are untouched.

Fresh scripts/verify fast output:

WARN load5=8.04 exceeds online CPU count=8; timing-sensitive checks may be delayed
PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

Full log: /tmp/port-ab-fast-sidebar-rows.log.

The browser replay is deferred again: at 03:09 UTC load5 was 6.84, but pgrep -af 'scripts/verify' showed another worktree's port-c3 browser suite (PID 927959). The DnD state probe commit 8034267 is also still awaiting that browser replay.

Side-by-side review of `/mnt/hdd/infraternal/artifacts/calternal-ref/shell-light-1440x900.png` and `/mnt/hdd/infraternal/artifacts/port-ab/sidebar-drag-light-1440x900.png` found the navigation rows were fixed at 38px, used a heavier accent-colored selected label, and had a 2px group-row gap. Calternal uses its responsive `--sidebar-row-h` (32px base scaled on fine pointers, 44px on touch), a 4px scaled list gap, a lighter 11% accent selection fill with ink text, and title-case section labels. Commit `39bdbfc` moves the shared row recipe to `SidebarChrome` so the preview and lazy sortable rows use the same styles; the group rows now use `--list-row-gap` and section headings match calternal's weight, tracking and case. DnD/persistence callbacks are untouched. Fresh `scripts/verify fast` output: ``` WARN load5=8.04 exceeds online CPU count=8; timing-sensitive checks may be delayed PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` Full log: `/tmp/port-ab-fast-sidebar-rows.log`. The browser replay is deferred again: at 03:09 UTC load5 was 6.84, but `pgrep -af 'scripts/verify'` showed another worktree's `port-c3` browser suite (PID 927959). The DnD state probe commit `8034267` is also still awaiting that browser replay.
Author
Owner

Verification update on branch port-c1, head 3f5eecf.

scripts/verify fast exited 0. Gate output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Verification update on branch `port-c1`, head `3f5eecf`. `scripts/verify fast` exited 0. Gate output: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Browser gate attempt collided with a newly started browser run from another worktree. At 03:19 UTC, 127.0.0.1:4175 was listening in /home/kayg/wt/port-c1 (PID 955313); scripts/verify browser exited before Playwright with Error: http://127.0.0.1:4175 is already used. No process was stopped. Waiting for the active browser gate to exit before retrying.

Browser gate attempt collided with a newly started browser run from another worktree. At 03:19 UTC, `127.0.0.1:4175` was listening in `/home/kayg/wt/port-c1` (PID 955313); `scripts/verify browser` exited before Playwright with `Error: http://127.0.0.1:4175 is already used`. No process was stopped. Waiting for the active browser gate to exit before retrying.
Author
Owner

Browser evidence: the first scripts/verify browser run failed at light/tablet/settings (768×1024). The “Page background” control extended to x=776.42 while the route content ended at x=768. Settings now switches to a single-column navigation/content layout when its available container is at most 36rem, so the breakpoint follows the shell’s remaining content width. The fast gate and browser rerun are underway.

Browser evidence: the first `scripts/verify browser` run failed at `light/tablet/settings` (768×1024). The “Page background” control extended to x=776.42 while the route content ended at x=768. Settings now switches to a single-column navigation/content layout when its available container is at most 36rem, so the breakpoint follows the shell’s remaining content width. The fast gate and browser rerun are underway.
Author
Owner

Operational note: I misspelled INFRATERNAL_ARTIFACT_DIR on the failed browser attempt. Playwright therefore used its default /mnt/hdd/infraternal/artifacts/port-ab output directory through the 768×1024 check. Those captures are not evidence for C3; the retry will set /mnt/hdd/infraternal/artifacts/port-c3 explicitly.

Operational note: I misspelled `INFRATERNAL_ARTIFACT_DIR` on the failed browser attempt. Playwright therefore used its default `/mnt/hdd/infraternal/artifacts/port-ab` output directory through the 768×1024 check. Those captures are not evidence for C3; the retry will set `/mnt/hdd/infraternal/artifacts/port-c3` explicitly.
Author
Owner

Browser verification update on branch port-c1, head 3f5eecf at the time of the run.

The browser gate passed JavaScript dependencies, Chromium installation, terminal fixture Playwright, web build, and release binary build. Playwright then stopped after sign-in because waitForDashboard still expected a route-owned h1; the shell title was visible as “Dashboard” while page heading inspection returned only Status, Hosts, and Needs attention. I updated route-title checks in scripts/browser-check.mjs to assert the shell title slot and will rerun the gates.

Browser verification update on branch `port-c1`, head `3f5eecf` at the time of the run. The browser gate passed JavaScript dependencies, Chromium installation, terminal fixture Playwright, web build, and release binary build. Playwright then stopped after sign-in because `waitForDashboard` still expected a route-owned `h1`; the shell title was visible as “Dashboard” while page heading inspection returned only Status, Hosts, and Needs attention. I updated route-title checks in `scripts/browser-check.mjs` to assert the shell title slot and will rerun the gates.
Author
Owner

Fast gate first run: web build, cargo fmt and cargo clippy passed. cargo test failed in crates/engine/src/logs.rs:349: steady_state_framing_does_not_allocate_per_chunk observed 111 allocations after warmup. This lane does not change the engine crate. At the time, another lane's browser gate and a release build were active; contention is a possible cause, so I will rerun after the shared jobs finish.

Fast gate first run: web build, cargo fmt and cargo clippy passed. `cargo test` failed in `crates/engine/src/logs.rs:349`: `steady_state_framing_does_not_allocate_per_chunk` observed 111 allocations after warmup. This lane does not change the engine crate. At the time, another lane's browser gate and a release build were active; contention is a possible cause, so I will rerun after the shared jobs finish.
Author
Owner

Verification update on branch port-c1, head 2ab2073.

scripts/verify fast exited 0 on this head. Gate output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Verification update on branch `port-c1`, head `2ab2073`. `scripts/verify fast` exited 0 on this head. Gate output: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Scripts/verify browser run 36 reached the production browser checks and failed at the first mobile sidebar item reorder (Hosts → Containers). The trusted touch pointerdown hit the drag handle’s nested SVG at y=237.92; at the end of the 1s activation wait the handle rectangle began at y=250.58, so it had shifted down 12.66 CSS px. The handle remained aria-pressed=false and the DnD operation probe was null. The run log is /tmp/port-ab-browser-run36.log. It measured initial route JS gzip at 113,715 bytes (under 120 KiB). I’m adding failure-only geometry/scroll diagnostics to identify when the shift occurs; the DnD assertion remains intact.

`Scripts/verify browser` run 36 reached the production browser checks and failed at the first mobile sidebar item reorder (Hosts → Containers). The trusted touch pointerdown hit the drag handle’s nested SVG at y=237.92; at the end of the 1s activation wait the handle rectangle began at y=250.58, so it had shifted down 12.66 CSS px. The handle remained `aria-pressed=false` and the DnD operation probe was null. The run log is `/tmp/port-ab-browser-run36.log`. It measured initial route JS gzip at 113,715 bytes (under 120 KiB). I’m adding failure-only geometry/scroll diagnostics to identify when the shift occurs; the DnD assertion remains intact.
Author
Owner

The corrected browser run passed the prior 768×1024 Settings overflow check, then stopped later in the shared mobile shell checks (checkMobileRenameFocus / dispatchTouchDrag). On the Containers reorder handle, the touchstart was trusted and targeted BUTTON.drag-handle, but aria-pressed stayed false where the check expected true. This is outside C3 page ownership; no unrelated sidebar code or assertion was changed. I will retry the browser gate when its slot is free.

The corrected browser run passed the prior 768×1024 Settings overflow check, then stopped later in the shared mobile shell checks (`checkMobileRenameFocus` / `dispatchTouchDrag`). On the Containers reorder handle, the touchstart was trusted and targeted `BUTTON.drag-handle`, but `aria-pressed` stayed `false` where the check expected `true`. This is outside C3 page ownership; no unrelated sidebar code or assertion was changed. I will retry the browser gate when its slot is free.
Author
Owner

Browser verification update on branch port-c1, head 2ab2073 at the time of the run.

The retry passed dependency setup, Chromium installation, terminal fixture Playwright, web build, and release binary build. Playwright reached the log controls and failed because checkLogControls still queried the Stream filter as a button after the route changed it to a native select. The run also measured METRIC container-detail JS gzip before terminal: 122949 bytes, 69 bytes above the 122,880-byte cold-route budget. I updated the check to use the combobox, added a detail-route budget assertion with script-size evidence, and shortened nonessential route copy; the next verification will confirm the budget.

Browser verification update on branch `port-c1`, head `2ab2073` at the time of the run. The retry passed dependency setup, Chromium installation, terminal fixture Playwright, web build, and release binary build. Playwright reached the log controls and failed because `checkLogControls` still queried the Stream filter as a button after the route changed it to a native select. The run also measured `METRIC container-detail JS gzip before terminal: 122949 bytes`, 69 bytes above the 122,880-byte cold-route budget. I updated the check to use the combobox, added a detail-route budget assertion with script-size evidence, and shortened nonessential route copy; the next verification will confirm the budget.
Author
Owner

Verification update on branch port-c1, head 3ed9126.

scripts/verify fast exited 0 on this head. Gate output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Verification update on branch `port-c1`, head `3ed9126`. `scripts/verify fast` exited 0 on this head. Gate output: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

The first browser gate invocation stopped before app checks: terminal fixture Playwright reported http://127.0.0.1:4175 is already used. Read-only socket inspection identified a Vite test fixture on that port. packages/terminal/playwright.config.ts supports INFRATERMINAL_TERMINAL_TEST_PORT; I will rerun on an unused port (4176) after the current shared browser gate finishes. No listener was stopped or modified.

The first browser gate invocation stopped before app checks: terminal fixture Playwright reported `http://127.0.0.1:4175 is already used`. Read-only socket inspection identified a Vite test fixture on that port. `packages/terminal/playwright.config.ts` supports `INFRATERMINAL_TERMINAL_TEST_PORT`; I will rerun on an unused port (4176) after the current shared browser gate finishes. No listener was stopped or modified.
Author
Owner

Run 37 passed the mobile item and group drag flows with the geometry-settling helper, then exposed a timing flaw in checkDeviceAuthorization: it asserted slow_down after completing the approval UI, by which point the initial poll interval had elapsed and the server correctly issued the approved token. I moved the throttle check to immediately after initiation, before the review UI, and made its error report status/code only. The failed run log is /tmp/port-ab-browser-run37.log; the response payload was redacted. Commits: 66aec76 (settled touch geometry), 26cead7 (throttle assertion timing).

Run 37 passed the mobile item and group drag flows with the geometry-settling helper, then exposed a timing flaw in `checkDeviceAuthorization`: it asserted `slow_down` after completing the approval UI, by which point the initial poll interval had elapsed and the server correctly issued the approved token. I moved the throttle check to immediately after initiation, before the review UI, and made its error report status/code only. The failed run log is `/tmp/port-ab-browser-run37.log`; the response payload was redacted. Commits: `66aec76` (settled touch geometry), `26cead7` (throttle assertion timing).
Author
Owner

A subsequent corrected browser retry cleared the mobile sidebar touch assertion but failed later in the shared checkLogControls flow: “Jump to latest” remained visible after the check expected it hidden (scripts/browser-check.mjs:1581). This is outside the C3 routes and was not changed. I will retry when the browser slot is available; C3 artifact output continues to use the port-c3 directory.

A subsequent corrected browser retry cleared the mobile sidebar touch assertion but failed later in the shared `checkLogControls` flow: “Jump to latest” remained visible after the check expected it hidden (`scripts/browser-check.mjs:1581`). This is outside the C3 routes and was not changed. I will retry when the browser slot is available; C3 artifact output continues to use the port-c3 directory.
Author
Owner

Run 38 also lost a startup race on port 4175. Preflight at 04:17 UTC showed no active verification process and no listener; a port-c1 browser gate claimed the port before Playwright started. Our gate exited before the suite and no process was stopped. Waiting for that browser gate to exit before retrying.

Run 38 also lost a startup race on port 4175. Preflight at 04:17 UTC showed no active verification process and no listener; a `port-c1` browser gate claimed the port before Playwright started. Our gate exited before the suite and no process was stopped. Waiting for that browser gate to exit before retrying.
Author
Owner

The browser gate reached the release server, then failed in checkTerminalRequestFailures: /terminals did not expose the New terminal page primary action. Source inspection confirms AuthenticatedShellBody passes chrome.page to ModeHeader, but the shell does not render page.primary/PrimaryPill; PrimaryPill.svelte is currently only exported. C2 is explicitly barred from editing the shell, so lane B must integrate the primary action for terminal creation from a non-empty session list and for the target-error dialog check. I will keep that gap visible in browser evidence and continue with the independent UI/API checks.

The browser gate reached the release server, then failed in `checkTerminalRequestFailures`: `/terminals` did not expose the `New terminal` page primary action. Source inspection confirms `AuthenticatedShellBody` passes `chrome.page` to `ModeHeader`, but the shell does not render `page.primary`/`PrimaryPill`; `PrimaryPill.svelte` is currently only exported. C2 is explicitly barred from editing the shell, so lane B must integrate the primary action for terminal creation from a non-empty session list and for the target-error dialog check. I will keep that gap visible in browser evidence and continue with the independent UI/API checks.
Author
Owner

Browser budget follow-up on branch port-c1, head 3ed9126.

The container-detail cold JavaScript assertion now fails with a measured 122,897 bytes against the 122,880-byte limit (17 bytes over). The route's copy reduction lowered the earlier 122,949-byte measurement by 52 bytes. The browser output includes the per-script gzip breakdown; I am tightening more nonessential detail copy, then will rerun.

Browser budget follow-up on branch `port-c1`, head `3ed9126`. The container-detail cold JavaScript assertion now fails with a measured 122,897 bytes against the 122,880-byte limit (17 bytes over). The route's copy reduction lowered the earlier 122,949-byte measurement by 52 bytes. The browser output includes the per-script gzip breakdown; I am tightening more nonessential detail copy, then will rerun.
Author
Owner

Verification update on branch port-c1, head 6fe48fe.

scripts/verify fast exited 0 on this head. Gate output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Verification update on branch `port-c1`, head `6fe48fe`. `scripts/verify fast` exited 0 on this head. Gate output: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

The latest full browser retry again reproduced the shared checkMobileRenameFocus touch-reorder failure (aria-pressed=false after a trusted touchstart on the Containers drag handle); a separate run failed at shared log controls. These are outside C3 and all assertions remain enabled. I added a signed-in Settings capture pass before the broad interaction checks for light/dark at 1440×900 and 390×844, restoring the saved local appearance state afterward so requested C3 screenshots are generated even if a later unrelated check stops the gate. scripts/verify fast passes after the change.

The latest full browser retry again reproduced the shared `checkMobileRenameFocus` touch-reorder failure (`aria-pressed=false` after a trusted touchstart on the Containers drag handle); a separate run failed at shared log controls. These are outside C3 and all assertions remain enabled. I added a signed-in Settings capture pass before the broad interaction checks for light/dark at 1440×900 and 390×844, restoring the saved local appearance state afterward so requested C3 screenshots are generated even if a later unrelated check stops the gate. `scripts/verify fast` passes after the change.
Author
Owner

Verification update on branch port-c1, head 8093a24.

scripts/verify fast exited 0 on this head. Gate output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Verification update on branch `port-c1`, head `8093a24`. `scripts/verify fast` exited 0 on this head. Gate output: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

The second C2 browser run captured the full list/dialog/menu/settings matrix and exercised the real AI token mint, same-key non-secret replay, and revoke. It measured /ai-agent-tokens at 121,297 gzip bytes (budget: 122,880). The run then failed the success-path focus assertion: focus did not return to #tokens-heading after a confirmed revoke. Inspection showed the dialog trap correctly retains its opener for Cancel/Escape, so I am adding an explicit focus move to the list heading after the successful list refresh; the browser cleanup assertion now marks a server-confirmed revoke as complete before checking focus.

The second C2 browser run captured the full list/dialog/menu/settings matrix and exercised the real AI token mint, same-key non-secret replay, and revoke. It measured `/ai-agent-tokens` at 121,297 gzip bytes (budget: 122,880). The run then failed the success-path focus assertion: focus did not return to `#tokens-heading` after a confirmed revoke. Inspection showed the dialog trap correctly retains its opener for Cancel/Escape, so I am adding an explicit focus move to the list heading after the successful list refresh; the browser cleanup assertion now marks a server-confirmed revoke as complete before checking focus.
Author
Owner

Visual comparison finding: the fixed Workspace label and sortable group labels were uppercase and heavier than calternal's muted title-case section labels. Commit b2b25c1 centralizes both label selectors in SidebarChrome using calternal's caption size, 560 weight and 0.02em tracking; the components retain their row padding, truncation and drag behavior.

/tmp/port-ab-fast-section-labels.log reports all fast checks passing. The browser slot is currently occupied by /home/kayg/wt/port-c2 (PID 1100364); the next visual gate is pending its completion.

Visual comparison finding: the fixed Workspace label and sortable group labels were uppercase and heavier than calternal's muted title-case section labels. Commit `b2b25c1` centralizes both label selectors in `SidebarChrome` using calternal's caption size, 560 weight and 0.02em tracking; the components retain their row padding, truncation and drag behavior. `/tmp/port-ab-fast-section-labels.log` reports all fast checks passing. The browser slot is currently occupied by `/home/kayg/wt/port-c2` (PID 1100364); the next visual gate is pending its completion.
Author
Owner

Browser update on branch port-c1, head 8093a24 at the time of the run.

The cold container-detail route measured 122,838 bytes, within the 122,880-byte limit. Playwright then failed the existing visible-text overlap assertion at the terminal prompt: the long collapsed shell title overlapped a visible log line after the page scrolls. I added a route-scoped 15rem visual maximum to the shell title text while preserving its full DOM/accessibility text in ea11318. The next browser run will verify the overlap and remaining interaction checks.

Browser update on branch `port-c1`, head `8093a24` at the time of the run. The cold container-detail route measured 122,838 bytes, within the 122,880-byte limit. Playwright then failed the existing visible-text overlap assertion at the terminal prompt: the long collapsed shell title overlapped a visible log line after the page scrolls. I added a route-scoped 15rem visual maximum to the shell title text while preserving its full DOM/accessibility text in `ea11318`. The next browser run will verify the overlap and remaining interaction checks.
Author
Owner

Verification update on branch port-c1, head ea11318.

scripts/verify fast exited 0 on this head. Gate output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Verification update on branch `port-c1`, head `ea11318`. `scripts/verify fast` exited 0 on this head. Gate output: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

The browser attempt after the screenshot-capture change stopped before the release build: the terminal fixture’s default port 4175 was already in use. The fixture config reads INFRATERMINAL_TERMINAL_TEST_PORT; the next C3 run will set it to a unique port (16873) and keep INFRATERNAL_ARTIFACT_DIR pointed at port-c3.

The browser attempt after the screenshot-capture change stopped before the release build: the terminal fixture’s default port 4175 was already in use. The fixture config reads `INFRATERMINAL_TERMINAL_TEST_PORT`; the next C3 run will set it to a unique port (16873) and keep `INFRATERNAL_ARTIFACT_DIR` pointed at `port-c3`.
Author
Owner

Browser rerun after f698ab3 progressed through AI token mint, same-key non-secret replay, revoke, and focus restoration, then timed out waiting for the inherited Containers heading. The C2 screenshot/token checks had navigated the shared browser page away from the container logs route. I moved them to a separate page and stopped persisting screenshot theme changes from that page. node --check and git diff --check pass; browser rerun is pending the active port-ab browser gate.

Browser rerun after `f698ab3` progressed through AI token mint, same-key non-secret replay, revoke, and focus restoration, then timed out waiting for the inherited Containers heading. The C2 screenshot/token checks had navigated the shared browser page away from the container logs route. I moved them to a separate page and stopped persisting screenshot theme changes from that page. `node --check` and `git diff --check` pass; browser rerun is pending the active port-ab browser gate.
Author
Owner

Browser scheduling update on branch port-c1, head ea11318.

A port-c2 browser run started after C1's preflight, briefly leaving two browser suites/release builds active. To restore the single-run limit, I sent SIGINT only to C1's own process group 1112734; that run exited 130 during the release build. Port-c2 was not signaled and is now the only active verifier/release build. C1 will retry after it clears.

Browser scheduling update on branch `port-c1`, head `ea11318`. A port-c2 browser run started after C1's preflight, briefly leaving two browser suites/release builds active. To restore the single-run limit, I sent SIGINT only to C1's own process group `1112734`; that run exited 130 during the release build. Port-c2 was not signaled and is now the only active verifier/release build. C1 will retry after it clears.
Author
Owner

Run 39 evidence: METRIC initial route JS gzip: 113712 bytes; the browser suite passed build, terminal paths, performance checks and desktop-light captures, then failed the first mobile Hosts → Containers touch reorder. The failure diagnostic measured a 28×28 drag handle before enabling Chromium touch emulation, then showed its live size at 44×44. SortableNavItem.svelte has the 44px size under @media (pointer: coarse), so the helper's stale start coordinates hit an SVG outside the drag handle; dnd-kit had no active sensor or operation. The same shape appeared in run36; run37 passed intermittently. I’m correcting measurement order by enabling coarse pointer mode before scroll/geometry sampling, preserving the drag assertions. Log: /tmp/port-ab-browser-run39.log.

Run 39 evidence: `METRIC initial route JS gzip: 113712 bytes`; the browser suite passed build, terminal paths, performance checks and desktop-light captures, then failed the first mobile Hosts → Containers touch reorder. The failure diagnostic measured a 28×28 drag handle before enabling Chromium touch emulation, then showed its live size at 44×44. `SortableNavItem.svelte` has the 44px size under `@media (pointer: coarse)`, so the helper's stale start coordinates hit an SVG outside the drag handle; dnd-kit had no active sensor or operation. The same shape appeared in run36; run37 passed intermittently. I’m correcting measurement order by enabling coarse pointer mode before scroll/geometry sampling, preserving the drag assertions. Log: `/tmp/port-ab-browser-run39.log`.
Author
Owner

The isolated C2 browser checks completed through the AI token mint/replay/revoke and focus assertions; its route JS metric was 121323 bytes gzip against the 122880-byte limit. The run then failed in the inherited container terminal browser flow at scripts/browser-check.mjs:2753: opening exec increased the /api/v1/stream WebSocket count, violating the existing same-tab multiplexing assertion. The C2 route captures and token assertions had passed before that assertion. The browser gate exited 1; I am recording this as a separate stream/container integration blocker outside C2-owned routes.

The isolated C2 browser checks completed through the AI token mint/replay/revoke and focus assertions; its route JS metric was 121323 bytes gzip against the 122880-byte limit. The run then failed in the inherited container terminal browser flow at `scripts/browser-check.mjs:2753`: opening exec increased the `/api/v1/stream` WebSocket count, violating the existing same-tab multiplexing assertion. The C2 route captures and token assertions had passed before that assertion. The browser gate exited 1; I am recording this as a separate stream/container integration blocker outside C2-owned routes.
Author
Owner

Committed d8e6df2 Measure mobile DnD targets in touch mode. The browser helper now enables CDP touch emulation and confirms (pointer: coarse) plus one touch point before scrolling and measuring. It retains the 3× stable-box check and all existing touch activation, row reorder and group reorder assertions. Its try/finally disables emulation and detaches CDP on measurement or interaction errors. node --check, git diff --check and all 16 scripts/verify fast checks passed; exact fast output: /tmp/port-ab-fast-touch-emulation-order.log. The next browser rerun is pending the other jobs' active browser gates.

Committed `d8e6df2 Measure mobile DnD targets in touch mode`. The browser helper now enables CDP touch emulation and confirms `(pointer: coarse)` plus one touch point before scrolling and measuring. It retains the 3× stable-box check and all existing touch activation, row reorder and group reorder assertions. Its `try/finally` disables emulation and detaches CDP on measurement or interaction errors. `node --check`, `git diff --check` and all 16 `scripts/verify fast` checks passed; exact fast output: `/tmp/port-ab-fast-touch-emulation-order.log`. The next browser rerun is pending the other jobs' active browser gates.
Author
Owner

Correction on the browser blocker: the failed assertion compared total historical /api/v1/stream WebSocket opens and did not record whether earlier sockets had closed, so that output did not establish simultaneous duplicate connections. I updated the check to assert the intended per-tab invariant directly: no more than one live stream WebSocket after opening exec. This still fails if a duplicate connection remains live. Verify-24 currently owns the browser slot; fast and browser reruns will follow when it clears.

Correction on the browser blocker: the failed assertion compared total historical `/api/v1/stream` WebSocket opens and did not record whether earlier sockets had closed, so that output did not establish simultaneous duplicate connections. I updated the check to assert the intended per-tab invariant directly: no more than one live stream WebSocket after opening exec. This still fails if a duplicate connection remains live. Verify-24 currently owns the browser slot; fast and browser reruns will follow when it clears.
Author
Owner

Browser follow-up on branch port-c1, head ea11318 at the time of the run.

The container-detail cold-route measurement was 122,873 bytes, under the 122,880-byte budget. Log filtering and terminal DATA/CREDIT checks passed. The visible-text overlap assertion still found the truncated shell title overlapping the stdout badge after scrolling. In 7b74178 the title is capped to 11rem only while the detail route's shell header is collapsed; it remains full width at the top and retains the full underlying text. I will verify the final width and screenshots in the next browser run.

Browser follow-up on branch `port-c1`, head `ea11318` at the time of the run. The container-detail cold-route measurement was 122,873 bytes, under the 122,880-byte budget. Log filtering and terminal DATA/CREDIT checks passed. The visible-text overlap assertion still found the truncated shell title overlapping the `stdout` badge after scrolling. In `7b74178` the title is capped to 11rem only while the detail route's shell header is collapsed; it remains full width at the top and retains the full underlying text. I will verify the final width and screenshots in the next browser run.
Author
Owner

Verification update on branch port-c1, head 7b74178.

scripts/verify fast exited 0 on this head. Gate output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Verification update on branch `port-c1`, head `7b74178`. `scripts/verify fast` exited 0 on this head. Gate output: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Browser update on branch port-c1, head 7b74178 at the time of the run.

The detail route measured 122875 bytes gzip (within the 122,880-byte limit). The 11rem collapsed-title cap cleared the desktop overlap, and Playwright advanced through the terminal accounting and color checks. At 390×844, the title still overlapped the Jump to latest log control. I reduced the cap to 9rem at phone widths in 958875; the full title text remains present for accessibility. The next browser run will verify this change and capture the final screenshots.

Browser update on branch `port-c1`, head `7b74178` at the time of the run. The detail route measured `122875` bytes gzip (within the 122,880-byte limit). The 11rem collapsed-title cap cleared the desktop overlap, and Playwright advanced through the terminal accounting and color checks. At 390×844, the title still overlapped the `Jump to latest` log control. I reduced the cap to 9rem at phone widths in `958875`; the full title text remains present for accessibility. The next browser run will verify this change and capture the final screenshots.
Author
Owner

Verification update on branch port-c1, head 958875d.

scripts/verify fast exited 0 on this head. Gate output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Verification update on branch `port-c1`, head `958875d`. `scripts/verify fast` exited 0 on this head. Gate output: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Run40 was started after a clear preflight (load5 2.46, no other browser/integration gate, port 4175 free), fixture port 16873. While it was building the release binary, port-c2 began a browser gate. To preserve the one-browser-suite-at-a-time rule, I stopped only this job's process group with SIGINT (exit 130) and left port-c2 untouched. The run had not reached Playwright; no assertion failed. Log: /tmp/port-ab-browser-run40.log. Next browser run after the slot clears will use fresh fixture port 16874.

Run40 was started after a clear preflight (load5 2.46, no other browser/integration gate, port 4175 free), fixture port 16873. While it was building the release binary, `port-c2` began a browser gate. To preserve the one-browser-suite-at-a-time rule, I stopped only this job's process group with SIGINT (exit 130) and left `port-c2` untouched. The run had not reached Playwright; no assertion failed. Log: `/tmp/port-ab-browser-run40.log`. Next browser run after the slot clears will use fresh fixture port 16874.
Author
Owner

The latest browser run measured 2 live /api/v1/stream sockets before the inherited container exec action and 3 afterward, so the current gate failure is a real additional live connection in that flow. I moved the C2 real-session pagination check earlier onto its isolated browser page. It will verify the 50-row cursor page and next_cursor, measure the terminal route JS budget, and capture populated desktop/mobile and light/dark session-list screenshots before the unrelated container assertion can abort the run. Dialog checks remain covered by the earlier empty-state CTA when the shell primary is absent.

The latest browser run measured 2 live `/api/v1/stream` sockets before the inherited container exec action and 3 afterward, so the current gate failure is a real additional live connection in that flow. I moved the C2 real-session pagination check earlier onto its isolated browser page. It will verify the 50-row cursor page and `next_cursor`, measure the terminal route JS budget, and capture populated desktop/mobile and light/dark session-list screenshots before the unrelated container assertion can abort the run. Dialog checks remain covered by the earlier empty-state CTA when the shell primary is absent.
Author
Owner

Run 41 measured METRIC initial route JS gzip: 113712 bytes and passed the previously flaky mobile touch DnD paths: item reorder/restore, group reorder, cross-group move and Reset arrangement. It then failed at scripts/browser-check.mjs:1234 because the assertion expected title="Sign out", while SidebarInteractive renders the custom warm tooltip as data-tooltip="Sign out" alongside its accessible aria-label. Commit cc03147 Assert the warm sign-out tooltip updates the assertion to the actual accessible tooltip attribute; it does not change the UI. node --check and git diff --check passed. Log: /tmp/port-ab-browser-run41.log.

Run 41 measured `METRIC initial route JS gzip: 113712 bytes` and passed the previously flaky mobile touch DnD paths: item reorder/restore, group reorder, cross-group move and Reset arrangement. It then failed at `scripts/browser-check.mjs:1234` because the assertion expected `title="Sign out"`, while `SidebarInteractive` renders the custom warm tooltip as `data-tooltip="Sign out"` alongside its accessible `aria-label`. Commit `cc03147 Assert the warm sign-out tooltip` updates the assertion to the actual accessible tooltip attribute; it does not change the UI. `node --check` and `git diff --check` passed. Log: `/tmp/port-ab-browser-run41.log`.
Author
Owner

Browser update on branch port-c1, head 958875d at the time of the run.

The cold container-detail route measured 122,875 bytes gzip (within 122,880). Mobile title spacing passed; the run also passed log, terminal, DATA/CREDIT, and Ghostty color checks. It then failed the dashboard typography assertion because .status-value rendered at weight 600 instead of calternal's expected 560. I am updating that count weight to 560 and will rerun the gates.

Browser update on branch `port-c1`, head `958875d` at the time of the run. The cold container-detail route measured 122,875 bytes gzip (within 122,880). Mobile title spacing passed; the run also passed log, terminal, DATA/CREDIT, and Ghostty color checks. It then failed the dashboard typography assertion because `.status-value` rendered at weight 600 instead of calternal's expected 560. I am updating that count weight to 560 and will rerun the gates.
Author
Owner

Run42 was started after a clear preflight (load5 2.20, no active browser/integration gate, port 4175 free), fixture port 16875. During the release build, stacks-images and port-c3 began browser suites. To preserve the one-suite-at-a-time rule, I stopped only run42's process group with SIGINT (exit 130) before Playwright started; the other jobs were left untouched. Log: /tmp/port-ab-browser-run42.log. The next run will wait for a clear slot and use fresh fixture port 16876.

Run42 was started after a clear preflight (load5 2.20, no active browser/integration gate, port 4175 free), fixture port 16875. During the release build, `stacks-images` and `port-c3` began browser suites. To preserve the one-suite-at-a-time rule, I stopped only run42's process group with SIGINT (exit 130) before Playwright started; the other jobs were left untouched. Log: `/tmp/port-ab-browser-run42.log`. The next run will wait for a clear slot and use fresh fixture port 16876.
Author
Owner

Verification update on branch port-c1, head 42b4803.

scripts/verify fast exited 0 on this head. Gate output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Verification update on branch `port-c1`, head `42b4803`. `scripts/verify fast` exited 0 on this head. Gate output: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Run43 preflight was clear: load5 2.69, no active browser/integration gate, port 4175 free. port-c1 began a browser gate between preflight and the terminal fixture startup and claimed 4175 (listener PID 1163180). Run43 exited before Playwright with Error: http://127.0.0.1:4175 is already used. The other gate was left untouched. Log: /tmp/port-ab-browser-run43.log; next retry after it exits will use fixture port 16877.

Run43 preflight was clear: load5 2.69, no active browser/integration gate, port 4175 free. `port-c1` began a browser gate between preflight and the terminal fixture startup and claimed 4175 (listener PID 1163180). Run43 exited before Playwright with `Error: http://127.0.0.1:4175 is already used`. The other gate was left untouched. Log: `/tmp/port-ab-browser-run43.log`; next retry after it exits will use fixture port 16877.
Author
Owner

Browser update on branch port-c1, head 42b4803 at the time of the run.

The detail route measured 122,875 bytes gzip. Dashboard typography, the 390×844 collapsed-title overlap, log controls, terminal accounting, and Ghostty color assertions all passed. Playwright then timed out because checkDeviceAuthorization still expected a route-owned h1 for /device; the C1 device page supplies its title through the shell. I updated that selector to assert the shell title and will rerun.

Browser update on branch `port-c1`, head `42b4803` at the time of the run. The detail route measured 122,875 bytes gzip. Dashboard typography, the 390×844 collapsed-title overlap, log controls, terminal accounting, and Ghostty color assertions all passed. Playwright then timed out because `checkDeviceAuthorization` still expected a route-owned h1 for `/device`; the C1 device page supplies its title through the shell. I updated that selector to assert the shell title and will rerun.
Author
Owner

The C2-first browser run now reaches real session creation before the inherited container check. openTerminalWorkspaceTab waited 10 seconds for data-session-id, but it remained empty; TerminalPane requires OPEN_OK.replay_start before recording the session ID. The base packages/stream OpenResult drops replay_start (the reviewed #34 fix is in pages-shadcn), so no session was created and the paginated/populated-list check could not continue. This shared stream parser is outside the C2-owned route files. The empty-state list, dialogs, menus, AI token flow, and token route budget ran before this failure.

The C2-first browser run now reaches real session creation before the inherited container check. `openTerminalWorkspaceTab` waited 10 seconds for `data-session-id`, but it remained empty; `TerminalPane` requires `OPEN_OK.replay_start` before recording the session ID. The base `packages/stream` `OpenResult` drops `replay_start` (the reviewed #34 fix is in `pages-shadcn`), so no session was created and the paginated/populated-list check could not continue. This shared stream parser is outside the C2-owned route files. The empty-state list, dialogs, menus, AI token flow, and token route budget ran before this failure.
Author
Owner

Fast gate on port-c1 at a5a320b097dc9b97b1c81575fb937a932b907b3c:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Fast gate on `port-c1` at `a5a320b097dc9b97b1c81575fb937a932b907b3c`: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Browser gate finding on a5a320b: all route interaction checks and the container-detail gzip budget passed (122,875 bytes), but the desktop dashboard screenshot setup could not scroll #main-content by 180px. The capture helper tried to extend the fixed-height shell scroller with its own padding. I’m changing the browser-only helper to append a temporary spacer inside route content, so the top-bar capture actually scrolls route content and the spacer is removed immediately after capture.

Browser gate finding on `a5a320b`: all route interaction checks and the container-detail gzip budget passed (122,875 bytes), but the desktop dashboard screenshot setup could not scroll `#main-content` by 180px. The capture helper tried to extend the fixed-height shell scroller with its own padding. I’m changing the browser-only helper to append a temporary spacer inside route content, so the top-bar capture actually scrolls route content and the spacer is removed immediately after capture.
Author
Owner

Fast gate on port-c1 at 8fdec728ac6c7404fe72be778fcf65c35d81613a:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Fast gate on `port-c1` at `8fdec728ac6c7404fe72be778fcf65c35d81613a`: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Started preview integration on branch port-preview, based on origin/dev at f640461228c8bdeba95646e4909accba829c00df.

Started preview integration on branch `port-preview`, based on `origin/dev` at `f640461228c8bdeba95646e4909accba829c00df`.
Author
Owner

Captured integration heads: calternal-port 4a0d76d658633af80d34140ac98e953c04ff90ef, port-c1 8fdec72c363c33669845ca30dd27b8964af81133, port-c2 77f7a5090d945618478cd209b880a5298b6e84bf, and port-c3 617ae9bb715af5f31c312a66a032f9024030cf73. All three C branches have merge base e12176d2781f38cee03d365977421e947a0b6a60 with calternal-port; calternal-port is 48 commits ahead and 61 behind origin/dev, so the first integration is a true two-sided merge.

Captured integration heads: `calternal-port` `4a0d76d658633af80d34140ac98e953c04ff90ef`, `port-c1` `8fdec72c363c33669845ca30dd27b8964af81133`, `port-c2` `77f7a5090d945618478cd209b880a5298b6e84bf`, and `port-c3` `617ae9bb715af5f31c312a66a032f9024030cf73`. All three C branches have merge base `e12176d2781f38cee03d365977421e947a0b6a60` with `calternal-port`; `calternal-port` is 48 commits ahead and 61 behind `origin/dev`, so the first integration is a true two-sided merge.
Author
Owner

C3 settings finish

Branch port-c3, HEAD 617ae9bb715af5f31c312a66a032f9024030cf73.

Gate output

scripts/verify fast (verbatim):

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

scripts/verify browser (verbatim status and failure):

PASS browser: JavaScript dependencies
PASS browser: install Chromium and system dependencies
PASS browser: terminal fixture Playwright
PASS browser: build web app
PASS browser: build release binary
FAIL browser: Playwright against release server
TimeoutError: waitForResponse: Timeout 30000ms exceeded while waiting for event "response"
TimeoutError: fill: Timeout 30000ms exceeded.
      at setContainerSearch (/home/kayg/wt/port-c3/scripts/browser-check.mjs:706:16)

The Settings pre-capture and its clean-layout checks passed in both themes and both viewports before the full suite stopped. The final failure is in the shared Containers search interaction: #container-search was not visible. Earlier full-suite retries also stopped in shared mobile sidebar and log-control checks; no unrelated assertions or UI were changed.

Screenshots

All are exact viewport captures in /mnt/hdd/infraternal/artifacts/port-c3/:

  • light-1440x900-settings.png — 1440×900
  • dark-1440x900-settings.png — 1440×900
  • light-390x844-settings.png — 390×844
  • dark-390x844-settings.png — 390×844

Differences from calternal

  • Settings stays inside infraternal’s shell, with the shell title/menu and a Profile/Appearance page rail. Calternal’s desktop reference is a standalone settings panel; its mobile reference is a bottom sheet with a back control.
  • The page contains only working Profile and Appearance destinations. Calternal’s Notifications, Calendars, AI, Photos, Plugins and Admin destinations are omitted because those settings are not implemented here.
  • Appearance exposes the lane A palette picker, its theme gradient, and a custom solid colour. The reference also shows system theme mode and additional photo backgrounds; those controls are absent from the working lane A preference state, so they are not presented.
## C3 settings finish Branch `port-c3`, HEAD `617ae9bb715af5f31c312a66a032f9024030cf73`. ### Gate output `scripts/verify fast` (verbatim): ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` `scripts/verify browser` (verbatim status and failure): ```text PASS browser: JavaScript dependencies PASS browser: install Chromium and system dependencies PASS browser: terminal fixture Playwright PASS browser: build web app PASS browser: build release binary FAIL browser: Playwright against release server TimeoutError: waitForResponse: Timeout 30000ms exceeded while waiting for event "response" TimeoutError: fill: Timeout 30000ms exceeded. at setContainerSearch (/home/kayg/wt/port-c3/scripts/browser-check.mjs:706:16) ``` The Settings pre-capture and its clean-layout checks passed in both themes and both viewports before the full suite stopped. The final failure is in the shared Containers search interaction: `#container-search` was not visible. Earlier full-suite retries also stopped in shared mobile sidebar and log-control checks; no unrelated assertions or UI were changed. ### Screenshots All are exact viewport captures in `/mnt/hdd/infraternal/artifacts/port-c3/`: - `light-1440x900-settings.png` — 1440×900 - `dark-1440x900-settings.png` — 1440×900 - `light-390x844-settings.png` — 390×844 - `dark-390x844-settings.png` — 390×844 ### Differences from calternal - Settings stays inside infraternal’s shell, with the shell title/menu and a Profile/Appearance page rail. Calternal’s desktop reference is a standalone settings panel; its mobile reference is a bottom sheet with a back control. - The page contains only working Profile and Appearance destinations. Calternal’s Notifications, Calendars, AI, Photos, Plugins and Admin destinations are omitted because those settings are not implemented here. - Appearance exposes the lane A palette picker, its theme gradient, and a custom solid colour. The reference also shows system theme mode and additional photo backgrounds; those controls are absent from the working lane A preference state, so they are not presented.
Author
Owner

Run44’s 390×844 Dashboard capture showed Search, Notifications and Account duplicated in the page header while the sidebar was closed, truncating the title. ModeHeader already defines the phone layout with app actions in the sidebar sheet. Commit 4a0d76d passes sidebar.isMobile to that prop and adds browser checks that the Dashboard title fits and the three app actions are visible in the drawer.

Evidence: target /mnt/hdd/infraternal/artifacts/port-ab/light-390x844-dashboard.png; reference /mnt/hdd/infraternal/artifacts/calternal-ref/shell-light-390x844.png.

node --check scripts/browser-check.mjs and git diff --check passed. scripts/verify fast output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

The final browser run and refreshed comparison plates are pending the shared browser/integration slot.

Run44’s 390×844 Dashboard capture showed Search, Notifications and Account duplicated in the page header while the sidebar was closed, truncating the title. `ModeHeader` already defines the phone layout with app actions in the sidebar sheet. Commit `4a0d76d` passes `sidebar.isMobile` to that prop and adds browser checks that the Dashboard title fits and the three app actions are visible in the drawer. Evidence: target `/mnt/hdd/infraternal/artifacts/port-ab/light-390x844-dashboard.png`; reference `/mnt/hdd/infraternal/artifacts/calternal-ref/shell-light-390x844.png`. `node --check scripts/browser-check.mjs` and `git diff --check` passed. `scripts/verify fast` output: ``` PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` The final browser run and refreshed comparison plates are pending the shared browser/integration slot.
Author
Owner

The latest browser run’s raw WebSocket instrumentation confirmed OPEN_OK contains both session_id and numeric replay_start, while the terminal pane still fails to record its session ID. The missing field is in the base packages/stream TypeScript parser; the required #34 change adds OpenResult.replay_start and validates/copies it. The same run measured 329160 bytes gzip only after the lazy terminal runtime loaded. I moved the 122880-byte assertion to the initial cold /terminals navigation, before that runtime import, and will record its verified value on the next browser run.

The latest browser run’s raw WebSocket instrumentation confirmed `OPEN_OK` contains both `session_id` and numeric `replay_start`, while the terminal pane still fails to record its session ID. The missing field is in the base `packages/stream` TypeScript parser; the required #34 change adds `OpenResult.replay_start` and validates/copies it. The same run measured 329160 bytes gzip only after the lazy terminal runtime loaded. I moved the 122880-byte assertion to the initial cold `/terminals` navigation, before that runtime import, and will record its verified value on the next browser run.
Author
Owner

Integrated calternal-port through 4a0d76d658633af80d34140ac98e953c04ff90ef in merge commit fb78eb0. The merge conflicted in docs/UI.md, PrimaryNavGroup.svelte, Sidebar.svelte, scripts/browser-check.mjs, and scripts/verify. The UI spec and shell presentation follow calternal-port; the sidebar retains dev's persistence lifecycle. The browser checks use calternal's shell-specific desktop/mobile scenarios while retaining dev's sidebar persistence check and device poll interval assertion. The fast-gate output keeps the expanded dev metrics. node --check scripts/browser-check.mjs completed successfully.

Integrated `calternal-port` through `4a0d76d658633af80d34140ac98e953c04ff90ef` in merge commit `fb78eb0`. The merge conflicted in `docs/UI.md`, `PrimaryNavGroup.svelte`, `Sidebar.svelte`, `scripts/browser-check.mjs`, and `scripts/verify`. The UI spec and shell presentation follow calternal-port; the sidebar retains dev's persistence lifecycle. The browser checks use calternal's shell-specific desktop/mobile scenarios while retaining dev's sidebar persistence check and device poll interval assertion. The fast-gate output keeps the expanded dev metrics. `node --check scripts/browser-check.mjs` completed successfully.
Author
Owner

The port-c2 branch advanced while integration was underway: its current head is 624319148d18d2bb007ef35fcd52d3d694554bc2, one commit beyond the initially captured 77f7a5090d945618478cd209b880a5298b6e84bf. I’ll merge the current branch head when C2's ordered turn arrives.

The `port-c2` branch advanced while integration was underway: its current head is `624319148d18d2bb007ef35fcd52d3d694554bc2`, one commit beyond the initially captured `77f7a5090d945618478cd209b880a5298b6e84bf`. I’ll merge the current branch head when C2's ordered turn arrives.
Author
Owner

Merged the current port-c1 head 8fdec72c363c33669845ca30dd27b8964af81133 as merge commit 729bd6f; all C1 route changes applied without conflicts. The only conflict was in scripts/browser-check.mjs: I kept dev's authenticated-page/CDP measurement lifecycle, moved C1's 120 KiB container-detail budget assertion into its local script-size scope, and kept the page open because it is the main authenticated test page. node --check scripts/browser-check.mjs and git diff --check passed.

Merged the current `port-c1` head `8fdec72c363c33669845ca30dd27b8964af81133` as merge commit `729bd6f`; all C1 route changes applied without conflicts. The only conflict was in `scripts/browser-check.mjs`: I kept dev's authenticated-page/CDP measurement lifecycle, moved C1's 120 KiB container-detail budget assertion into its local script-size scope, and kept the page open because it is the main authenticated test page. `node --check scripts/browser-check.mjs` and `git diff --check` passed.
Author
Owner

Merged current port-c2 head 624319148d18d2bb007ef35fcd52d3d694554bc2 as merge commit 209db0e. Its terminal and AI-token routes applied cleanly. Six scripts/browser-check.mjs overlaps were resolved by combining C2's route title helper and route calls with dev's auth diagnostics, while retaining C2's owned browser-resource cleanup. node --check scripts/browser-check.mjs and git diff --check passed.

Merged current `port-c2` head `624319148d18d2bb007ef35fcd52d3d694554bc2` as merge commit `209db0e`. Its terminal and AI-token routes applied cleanly. Six `scripts/browser-check.mjs` overlaps were resolved by combining C2's route title helper and route calls with dev's auth diagnostics, while retaining C2's owned browser-resource cleanup. `node --check scripts/browser-check.mjs` and `git diff --check` passed.
Author
Owner

Merged current port-c3 head 617ae9bb715af5f31c312a66a032f9024030cf73 as merge commit d3f0191. Account and Settings routes applied cleanly. The browser-check conflict resolution preserves the C1/C2/C3 route matrix, validates each page's calternal shell title, retains C3's light/dark Settings screenshots, and keeps dev's sidebar persistence check and 1800-second lifecycle fixture. node --check scripts/browser-check.mjs and git diff --check passed.

Merged current `port-c3` head `617ae9bb715af5f31c312a66a032f9024030cf73` as merge commit `d3f0191`. Account and Settings routes applied cleanly. The browser-check conflict resolution preserves the C1/C2/C3 route matrix, validates each page's calternal shell title, retains C3's light/dark Settings screenshots, and keeps dev's sidebar persistence check and 1800-second lifecycle fixture. `node --check scripts/browser-check.mjs` and `git diff --check` passed.
Author
Owner

The browser gate retry on 8fdec72 began after the preflight found no running integration/browser suite. A port-ab browser suite started during C1's release build, briefly overlapping a second browser and release build. I stopped only the C1 process group (gate exit 130) to restore the one-suite limit; the run ended before C1's Playwright assertions. I will retry after the shared slot remains clear.

The browser gate retry on `8fdec72` began after the preflight found no running integration/browser suite. A port-ab browser suite started during C1's release build, briefly overlapping a second browser and release build. I stopped only the C1 process group (gate exit 130) to restore the one-suite limit; the run ended before C1's Playwright assertions. I will retry after the shared slot remains clear.
Author
Owner

Fast-gate finding and merge fix: the initial scripts/verify fast reached Vitest and failed 8 sidebar assertions. The calternal shell default had only Hosts and Containers; the merged branch also needed the working /terminals, /ai-agent-tokens, and /settings routes. The older dev expectations referenced routes absent from this checkout (stacks, images, volumes, users/agent/audit pages), contrary to DECISIONS.md §25. I added the three shipped links, kept unshipped links out, and updated arrangement/persistence expectations. Targeted web tests now pass: 2 files, 12 tests; git diff --check passes. Rerunning the full fast gate next.

Fast-gate finding and merge fix: the initial `scripts/verify fast` reached Vitest and failed 8 sidebar assertions. The calternal shell default had only Hosts and Containers; the merged branch also needed the working `/terminals`, `/ai-agent-tokens`, and `/settings` routes. The older dev expectations referenced routes absent from this checkout (`stacks`, `images`, `volumes`, users/agent/audit pages), contrary to DECISIONS.md §25. I added the three shipped links, kept unshipped links out, and updated arrangement/persistence expectations. Targeted web tests now pass: 2 files, 12 tests; `git diff --check` passes. Rerunning the full fast gate next.
Author
Owner

Merge-caused sidebar fix complete. The preview defaults now expose only the working pages in this merged checkout: Hosts, Containers, Terminals, AI agent tokens, and Settings. This preserves DECISIONS.md §25 (only working routes in the UI), while retaining the calternal shell. Focused sidebar tests passed (2 files, 12 tests). scripts/verify fast passed:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

Next: commit this fix, then build and point the dev-VM preview at port-preview without changing its data directory.

Merge-caused sidebar fix complete. The preview defaults now expose only the working pages in this merged checkout: Hosts, Containers, Terminals, AI agent tokens, and Settings. This preserves DECISIONS.md §25 (only working routes in the UI), while retaining the calternal shell. Focused sidebar tests passed (2 files, 12 tests). `scripts/verify fast` passed: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` Next: commit this fix, then build and point the dev-VM preview at `port-preview` without changing its data directory.
Author
Owner

Run on fixture port 16880 passed the mobile title/action-placement assertions and measured METRIC initial route JS gzip: 113724 bytes (<120 KiB). Playwright then failed in captureInboxOpen because the browser script still searched the closed phone header for Notifications after app actions moved into the sidebar sheet. Updated the mobile path to open the Sidebar dialog, trigger Notifications there on Dashboard and Hosts, verify focus return, and close the drawer afterward. The browser script passes node --check; the change is commit bfd278d. Full run output: /tmp/port-ab-browser-final3.log. Waiting for the active port-c2 browser gate before the next full run.

Run on fixture port 16880 passed the mobile title/action-placement assertions and measured `METRIC initial route JS gzip: 113724 bytes` (<120 KiB). Playwright then failed in `captureInboxOpen` because the browser script still searched the closed phone header for Notifications after app actions moved into the sidebar sheet. Updated the mobile path to open the Sidebar dialog, trigger Notifications there on Dashboard and Hosts, verify focus return, and close the drawer afterward. The browser script passes `node --check`; the change is commit `bfd278d`. Full run output: `/tmp/port-ab-browser-final3.log`. Waiting for the active `port-c2` browser gate before the next full run.
Author
Owner

Follow-up evidence on the capture helper: appending the temporary spacer to #route-content still left the measured #main-content range at 0 (scrollHeight === clientHeight). The shell route content has a viewport-sized minimum. The helper now appends the spacer as a direct child of the fixed-height scroller and returns the measured dimensions on failure.

Follow-up evidence on the capture helper: appending the temporary spacer to `#route-content` still left the measured `#main-content` range at 0 (`scrollHeight === clientHeight`). The shell route content has a viewport-sized minimum. The helper now appends the spacer as a direct child of the fixed-height scroller and returns the measured dimensions on failure.
Author
Owner

Run4 on fixture port 16881 passed build, the mobile title/action-placement assertion and inbox loading/glass/sheet-size checks. First-route JavaScript gzip measured 113724 bytes. Escape then failed because the Inbox sheet opened from inside the still-open modal Sidebar sheet; the screenshot shows both layers: /mnt/hdd/infraternal/artifacts/port-ab/inbox-open-light-390x844.png.

Commit c9123b2 closes the mobile sidebar and focuses its header toggle before opening Search or Inbox. The browser check now asserts the sidebar sheet is closed while Inbox is open and focus returns to the toggle. docs/UI.md records the behavior. node --check scripts/browser-check.mjs, git diff --check, and scripts/verify fast passed. Fast output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

Browser rerun is queued behind the active stacks-images integration gate.

Run4 on fixture port 16881 passed build, the mobile title/action-placement assertion and inbox loading/glass/sheet-size checks. First-route JavaScript gzip measured `113724 bytes`. Escape then failed because the Inbox sheet opened from inside the still-open modal Sidebar sheet; the screenshot shows both layers: `/mnt/hdd/infraternal/artifacts/port-ab/inbox-open-light-390x844.png`. Commit `c9123b2` closes the mobile sidebar and focuses its header toggle before opening Search or Inbox. The browser check now asserts the sidebar sheet is closed while Inbox is open and focus returns to the toggle. `docs/UI.md` records the behavior. `node --check scripts/browser-check.mjs`, `git diff --check`, and `scripts/verify fast` passed. Fast output: ``` PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` Browser rerun is queued behind the active `stacks-images` integration gate.
Author
Owner

Fast gate on port-c1 at 341bc71:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Fast gate on `port-c1` at `341bc71`: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Screenshot finding: the live Setup and Sign in DOM contains the form, but the fixed #app-background layer paints over it in Chromium captures; only the tabs appeared. packages/web/src/lib/styles/background.css documents that .app-frame must be positioned so application content paints above the background. The merged AppShell lacked this wrapper. I added .app-frame { position: relative; } around both auth and authenticated surfaces, and will rerun fast, redeploy, and refresh the auth screenshots. No existing preview account or data has been modified.

Screenshot finding: the live Setup and Sign in DOM contains the form, but the fixed `#app-background` layer paints over it in Chromium captures; only the tabs appeared. `packages/web/src/lib/styles/background.css` documents that `.app-frame` must be positioned so application content paints above the background. The merged `AppShell` lacked this wrapper. I added `.app-frame { position: relative; }` around both auth and authenticated surfaces, and will rerun fast, redeploy, and refresh the auth screenshots. No existing preview account or data has been modified.
Author
Owner

C2 performance update. Commit 073bc64cc1d31429016cfbc934dd6582cc03114f lazily imports DialogChrome when either terminal dialog opens and SegmentedControl when a dialog opens or restored workspace tabs require it. Fresh /terminals navigation does not request either component chunk. The previous cold measurement was 126001 bytes gzip against the 122880-byte budget; the browser gate will measure the fix after the current competing gates clear.

Focused check: bun --cwd=packages/web run check completed with svelte-check found 0 errors and 1 warning in 1 file; the remaining warning is the existing .sidebar-toggle svg selector in packages/web/src/lib/shell/SidebarChrome.svelte:109. The earlier scripts/verify fast run passed web build, fmt, and clippy, then failed the unrelated engine allocator test steady_state_framing_does_not_allocate_per_chunk at 102 allocations.

C2 performance update. Commit `073bc64cc1d31429016cfbc934dd6582cc03114f` lazily imports DialogChrome when either terminal dialog opens and SegmentedControl when a dialog opens or restored workspace tabs require it. Fresh `/terminals` navigation does not request either component chunk. The previous cold measurement was 126001 bytes gzip against the 122880-byte budget; the browser gate will measure the fix after the current competing gates clear. Focused check: `bun --cwd=packages/web run check` completed with `svelte-check found 0 errors and 1 warning in 1 file`; the remaining warning is the existing `.sidebar-toggle svg` selector in `packages/web/src/lib/shell/SidebarChrome.svelte:109`. The earlier `scripts/verify fast` run passed web build, fmt, and clippy, then failed the unrelated engine allocator test `steady_state_framing_does_not_allocate_per_chunk` at 102 allocations.
Author
Owner

The current calternal-port head had two post-capture commits (bfd278d, c9123b2); both are now in merge commit cdd9bd4c9115724945bd8fa84a59f68959d5e158. The shell change closes the mobile sidebar before opening Inbox or Quick Search, and docs/UI.md now specifies focus restoration. Resolved the scripts/browser-check.mjs overlap by combining the mobile drawer-scoped Notifications trigger with the preview's existing shell-title check. node --check scripts/browser-check.mjs and git diff --check pass. I am merging the newer C1 and C2 tips next.

The current `calternal-port` head had two post-capture commits (`bfd278d`, `c9123b2`); both are now in merge commit `cdd9bd4c9115724945bd8fa84a59f68959d5e158`. The shell change closes the mobile sidebar before opening Inbox or Quick Search, and `docs/UI.md` now specifies focus restoration. Resolved the `scripts/browser-check.mjs` overlap by combining the mobile drawer-scoped Notifications trigger with the preview's existing shell-title check. `node --check scripts/browser-check.mjs` and `git diff --check` pass. I am merging the newer C1 and C2 tips next.
Author
Owner

The newer C-lane heads are now included in order: port-c1 341bc7182d9e9f53a43e27751ae1204932c05cad merged cleanly as 4842426 (browser scroll fixture spacer now attaches to #main-content), followed by current port-c2 073bc64cc1d31429016cfbc934dd6582cc03114f merged cleanly as c2b67f025e6ee15d70779b6fb2267485ef3f3583 (terminal dialog controls lazy-load). No generated files were involved. Browser-harness node --check and git diff --check pass; rechecked lane refs still match these tips and C3's unchanged head. Running the final fast gate next.

The newer C-lane heads are now included in order: `port-c1` `341bc7182d9e9f53a43e27751ae1204932c05cad` merged cleanly as `4842426` (browser scroll fixture spacer now attaches to `#main-content`), followed by current `port-c2` `073bc64cc1d31429016cfbc934dd6582cc03114f` merged cleanly as `c2b67f025e6ee15d70779b6fb2267485ef3f3583` (terminal dialog controls lazy-load). No generated files were involved. Browser-harness `node --check` and `git diff --check` pass; rechecked lane refs still match these tips and C3's unchanged head. Running the final fast gate next.
Author
Owner

The first coarse-pointer inbox capture measured borderRadius: "18px" on all four corners. The sheet rule correctly used --radius-sheet on top corners, but the later touch-menu selector overrode it. Commit 7338b01 restricts the 18px touch-menu radius to non-sheet surfaces and updates the browser assertion to compare against --radius-menu/--radius-sheet directly. node --check scripts/browser-check.mjs, git diff --check, and all 16 scripts/verify fast steps passed; full output is /tmp/port-ab-fast-sheet-corner.log. Browser rerun is waiting for port-c1 to exit.

The first coarse-pointer inbox capture measured `borderRadius: "18px"` on all four corners. The sheet rule correctly used `--radius-sheet` on top corners, but the later touch-menu selector overrode it. Commit `7338b01` restricts the 18px touch-menu radius to non-sheet surfaces and updates the browser assertion to compare against `--radius-menu`/`--radius-sheet` directly. `node --check scripts/browser-check.mjs`, `git diff --check`, and all 16 `scripts/verify fast` steps passed; full output is `/tmp/port-ab-fast-sheet-corner.log`. Browser rerun is waiting for `port-c1` to exit.
Author
Owner

The scroll capture now succeeds: TOPBAR_SCROLL_SMOKE reported 90/90 moved frames with backdrop filtering enabled and disabled. The next route assertion found .mode-header .mh-title still reading Dashboard on /hosts, while its accessible label already said Hosts view. The host list was not registering page chrome; I’m registering the route with no title override so the shell displays its route-owned title.

The scroll capture now succeeds: `TOPBAR_SCROLL_SMOKE` reported 90/90 moved frames with backdrop filtering enabled and disabled. The next route assertion found `.mode-header .mh-title` still reading `Dashboard` on `/hosts`, while its accessible label already said `Hosts view`. The host list was not registering page chrome; I’m registering the route with no title override so the shell displays its route-owned title.
Author
Owner

Fast gate on port-c1 at 11b6f8f:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Fast gate on `port-c1` at `11b6f8f`: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Screenshot verification on the integrated branch found a merge mismatch: the fresh isolated account receives GET /api/v1/me/sidebar 200, then the ported UI saves only routes shipped in this preview and gets PUT /api/v1/me/sidebar 422. The server currently requires every stable route ID, including pages hidden under the “only working features” decision, so the UI shows a retry toast. This was observed only against a unique temporary database; the preview owner's data was not touched. I am fixing this contract mismatch on port-preview before taking the final screenshots.

Screenshot verification on the integrated branch found a merge mismatch: the fresh isolated account receives `GET /api/v1/me/sidebar` 200, then the ported UI saves only routes shipped in this preview and gets `PUT /api/v1/me/sidebar` 422. The server currently requires every stable route ID, including pages hidden under the “only working features” decision, so the UI shows a retry toast. This was observed only against a unique temporary database; the preview owner's data was not touched. I am fixing this contract mismatch on `port-preview` before taking the final screenshots.
Author
Owner

A second preflight/start race occurred at 11b6f8f: the verify queue was clear, then port-ab started a browser suite during C1 setup. I stopped only C1's process group (exit 130) before its server build/Playwright assertions completed. The interrupted attempt did not produce a gate result; C1 will retry after port-ab clears.

A second preflight/start race occurred at `11b6f8f`: the verify queue was clear, then port-ab started a browser suite during C1 setup. I stopped only C1's process group (exit 130) before its server build/Playwright assertions completed. The interrupted attempt did not produce a gate result; C1 will retry after port-ab clears.
Author
Owner

Cold-route browser measurement on the preceding implementation was 126547 bytes gzip, 3667 above the 122880-byte budget. I moved container and SSH target loading into the lazy TerminalDialogs.svelte component so fresh route visits no longer fetch those inventories until a dialog is opened. Pending host-detail SSH handoffs still use the dialog and keep unavailable targets retryable; loaded target labels are retained for session rows. The latest route Svelte check reports 0 errors and the existing SidebarChrome.svelte:109 unused-selector warning. Fast and browser gates are pending. The stream OPEN_OK.replay_start parser dependency remains on #34 and outside C2 ownership.

Cold-route browser measurement on the preceding implementation was 126547 bytes gzip, 3667 above the 122880-byte budget. I moved container and SSH target loading into the lazy `TerminalDialogs.svelte` component so fresh route visits no longer fetch those inventories until a dialog is opened. Pending host-detail SSH handoffs still use the dialog and keep unavailable targets retryable; loaded target labels are retained for session rows. The latest route Svelte check reports 0 errors and the existing `SidebarChrome.svelte:109` unused-selector warning. Fast and browser gates are pending. The stream `OPEN_OK.replay_start` parser dependency remains on #34 and outside C2 ownership.
Author
Owner

Integrated preview is live at http://infraternal-dev.vpn.kayg.org:7010 (also reached through the dev preview hostname). Final port-preview SHA: f610124120562158cef4645e6009f5abe9cd1817.

Current source heads merged, in the requested order:

  • calternal-port 7338b01ba9856ed376ba5cde5d3aa76691518ea2
  • port-c1 11b6f8fc7574279e70ce2ac46dd5c4ab8785dfb6
  • port-c2 a68274f4862f67a33b14e69bd4c28d586ce1125b
  • port-c3 617ae9bb715af5f31c312a66a032f9024030cf73

Shell and shared chrome follow calternal; page routes follow their C lane. Merge conflicts in the shell and browser harness were resolved by keeping the calternal shell and combining its mobile drawer/touch behavior with existing auth diagnostics and the C1/C2/C3 route checks. Later calternal, C1, and C2 heads merged cleanly. Generated API files were regenerated after a merge-caused sidebar mismatch was found: the UI hides unshipped routes, but the API required every stable route ID. The v1 contract/proto now accepts any non-empty subset of known IDs, allowing sidebar persistence while preserving the “only working features” UI rule.

PREVIEW_REF=port-preview scripts/preview deployed the final SHA. /api/health returned {"status":"ok","version":"0.0.1"} and / returned HTTP 200. The existing preview data directory was retained. There are 17 screenshots in /mnt/hdd/infraternal/artifacts/port-preview/; all requested captures are exactly 1440×900 or 390×844. Setup/sign-in and the auth-gated UI-test view were captured from live port 7010. Since the harness could not use the existing account’s passkey, authenticated Dashboard/UI-test captures used the final release binary with a unique temporary database and passkey; that temporary data was removed and the owner account was untouched.

Final scripts/verify fast output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

Browser gate skipped as requested. Two earlier fast attempts failed separate unrelated enrollment-CA and global allocator-count tests; each passed in isolation, and this final complete run passed.

To put the preview back on dev, run scripts/preview with no PREVIEW_REF override; the script defaults to dev. No push was made. Issue remains open.

Integrated preview is live at http://infraternal-dev.vpn.kayg.org:7010 (also reached through the dev preview hostname). Final `port-preview` SHA: `f610124120562158cef4645e6009f5abe9cd1817`. Current source heads merged, in the requested order: - `calternal-port` `7338b01ba9856ed376ba5cde5d3aa76691518ea2` - `port-c1` `11b6f8fc7574279e70ce2ac46dd5c4ab8785dfb6` - `port-c2` `a68274f4862f67a33b14e69bd4c28d586ce1125b` - `port-c3` `617ae9bb715af5f31c312a66a032f9024030cf73` Shell and shared chrome follow calternal; page routes follow their C lane. Merge conflicts in the shell and browser harness were resolved by keeping the calternal shell and combining its mobile drawer/touch behavior with existing auth diagnostics and the C1/C2/C3 route checks. Later calternal, C1, and C2 heads merged cleanly. Generated API files were regenerated after a merge-caused sidebar mismatch was found: the UI hides unshipped routes, but the API required every stable route ID. The v1 contract/proto now accepts any non-empty subset of known IDs, allowing sidebar persistence while preserving the “only working features” UI rule. `PREVIEW_REF=port-preview scripts/preview` deployed the final SHA. `/api/health` returned `{"status":"ok","version":"0.0.1"}` and `/` returned HTTP 200. The existing preview data directory was retained. There are 17 screenshots in `/mnt/hdd/infraternal/artifacts/port-preview/`; all requested captures are exactly 1440×900 or 390×844. Setup/sign-in and the auth-gated UI-test view were captured from live port 7010. Since the harness could not use the existing account’s passkey, authenticated Dashboard/UI-test captures used the final release binary with a unique temporary database and passkey; that temporary data was removed and the owner account was untouched. Final `scripts/verify fast` output: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` Browser gate skipped as requested. Two earlier fast attempts failed separate unrelated enrollment-CA and global allocator-count tests; each passed in isolation, and this final complete run passed. To put the preview back on `dev`, run `scripts/preview` with no `PREVIEW_REF` override; the script defaults to `dev`. No push was made. Issue remains open.
Author
Owner

UI review followed emil-design-eng, better-ui, better-layout, better-typography, better-colors, better-accessibility, better-writing, and better-interface. I checked shared token/surface use, responsive layouts at 1440×900 and 390×844, light/dark contrast, narrow-screen wrapping/truncation, concise labels/help text, and named controls in the captured screens. Capture contexts used reduced-motion preference.

UI review followed `emil-design-eng`, `better-ui`, `better-layout`, `better-typography`, `better-colors`, `better-accessibility`, `better-writing`, and `better-interface`. I checked shared token/surface use, responsive layouts at 1440×900 and 390×844, light/dark contrast, narrow-screen wrapping/truncation, concise labels/help text, and named controls in the captured screens. Capture contexts used reduced-motion preference.
Author
Owner

I found a C1 browser-gate invocation mistake: scripts/browser-check.mjs reads INFRATERNAL_ARTIFACT_DIR; my command used the misspelled INFRATERAL_ARTIFACT_DIR, so the runner fell back to its port-ab default. This may have overwritten same-named port-ab screenshot files, and the C1 artifact directory was not created. I will use the correctly spelled variable for the final run and write only to /mnt/hdd/infraternal/artifacts/port-c1.

I found a C1 browser-gate invocation mistake: `scripts/browser-check.mjs` reads `INFRATERNAL_ARTIFACT_DIR`; my command used the misspelled `INFRATERAL_ARTIFACT_DIR`, so the runner fell back to its `port-ab` default. This may have overwritten same-named port-ab screenshot files, and the C1 artifact directory was not created. I will use the correctly spelled variable for the final run and write only to `/mnt/hdd/infraternal/artifacts/port-c1`.
Author
Owner

Lane A/B complete on calternal-port.

Head: 7338b01ba9856ed376ba5cde5d3aa76691518ea2

First-load JavaScript gzip: 113,777 bytes (budget: 122,880 bytes).

Gates

scripts/verify fast:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

scripts/verify browser:

PASS browser: JavaScript dependencies
PASS browser: install Chromium and system dependencies
PASS browser: terminal fixture Playwright
PASS browser: build web app
PASS browser: build release binary
METRIC initial route JS gzip: 113777 bytes
METRIC browser log flood: {"recordsPerSecond":18248,"frames":109,"fps":60,"retained":10000,"bytes":210000,"dropped":81200,"renderedRows":18}
PASS browser: Playwright against release server
PASS browser: terminal production first-load budget

Screenshots

Raw captures are in /mnt/hdd/infraternal/artifacts/port-ab/:

  • Shell and Dashboard, light/dark, 1440×900 and 390×844: {light,dark}-{1440x900,390x844}.png and {light,dark}-{1440x900,390x844}-dashboard.png.
  • Open title menu, both themes and sizes: menu-open-{light,dark}-{1440x900,390x844}.png.
  • Open inbox, both themes and sizes: inbox-open-{light,dark}-{1440x900,390x844}.png.
  • Sidebar mid-drag: sidebar-drag-{light,dark}-1440x900.png.
  • Hosts list: {light,dark}-1440x900-hosts.png.

Side-by-side plates have the calternal reference on the left and infraternal on the right:

  • Shell: compare-final-shell-{light,dark}-{1440x900,390x844}.png.
  • Dashboard: compare-final-dashboard-{light,dark}-{1440x900,390x844}.png.
  • Menu: compare-final-menu-{light,dark}-{1440x900,390x844}.png.
  • Inbox: compare-final-inbox-{light,dark}-{1440x900,390x844}.png.
  • Sidebar mid-drag: compare-final-sidebar-drag-{light,dark}-1440x900.png.
  • Hosts list: compare-final-hosts-list-{light,dark}-1440x900.png.

Visible differences

  • The shared shell geometry, Paper/Noir background treatment, display-serif page title, floating glass sidebar, icon row, menu surface, and mobile sidebar toggle align closely with the references.
  • Calternal shows calendar events, file rows, and its bottom mobile mode bar. Infraternal shows Dashboard status/host cards, the Hosts data table, and keeps Search/Inbox/Account in the mobile sidebar drawer. The dashboard cards are larger summary panels; the Hosts page uses a compact table header and data row rather than the reference's folder rows.
  • The menu contents and anchors differ: calternal's reference is a Files action menu; infraternal's is the page-title navigation menu. Their glass treatment and desktop sizing match; the mobile infraternal menu is slightly narrower because its labels are shorter.
  • Calternal's dialog is a centered share form on desktop and a tall mobile sheet. Infraternal's working inbox is a top-right glass panel on desktop and a shorter bottom sheet on mobile; contents and dimensions follow the inbox panel mapping.
  • During reorder, infraternal shows its custom group row and blue drop/focus outline. Calternal has no sidebar reordering; the file list is the closest row-treatment reference.
  • The reference Appearance settings screen has no target screenshot or route: the settings stub and its nav/account action were removed under the owner's rule against unbuilt UI.

Removed unshipped surfaces

Removed navigation/routes for Stacks, Images, Volumes, Terminals, Users & Roles, AI agent tokens, infraternal agents, Audit Log, the Settings stub, and the duplicate placeholder Inbox page. The working Inbox remains available from the sidebar.

Removed Dashboard CPU, Memory and Disk “—” tiles and the fake Recent Activity/audit-log preview; also removed unsupported host telemetry, the fake inbox badge count, disabled SSH terminal action, and fake account Settings action. Audit Log returns with #38; Stacks, Images and Volumes return with #41 when those features ship.

Lane A/B complete on `calternal-port`. Head: `7338b01ba9856ed376ba5cde5d3aa76691518ea2` First-load JavaScript gzip: **113,777 bytes** (budget: 122,880 bytes). ## Gates `scripts/verify fast`: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` `scripts/verify browser`: ```text PASS browser: JavaScript dependencies PASS browser: install Chromium and system dependencies PASS browser: terminal fixture Playwright PASS browser: build web app PASS browser: build release binary METRIC initial route JS gzip: 113777 bytes METRIC browser log flood: {"recordsPerSecond":18248,"frames":109,"fps":60,"retained":10000,"bytes":210000,"dropped":81200,"renderedRows":18} PASS browser: Playwright against release server PASS browser: terminal production first-load budget ``` ## Screenshots Raw captures are in `/mnt/hdd/infraternal/artifacts/port-ab/`: - Shell and Dashboard, light/dark, 1440×900 and 390×844: `{light,dark}-{1440x900,390x844}.png` and `{light,dark}-{1440x900,390x844}-dashboard.png`. - Open title menu, both themes and sizes: `menu-open-{light,dark}-{1440x900,390x844}.png`. - Open inbox, both themes and sizes: `inbox-open-{light,dark}-{1440x900,390x844}.png`. - Sidebar mid-drag: `sidebar-drag-{light,dark}-1440x900.png`. - Hosts list: `{light,dark}-1440x900-hosts.png`. Side-by-side plates have the calternal reference on the left and infraternal on the right: - Shell: `compare-final-shell-{light,dark}-{1440x900,390x844}.png`. - Dashboard: `compare-final-dashboard-{light,dark}-{1440x900,390x844}.png`. - Menu: `compare-final-menu-{light,dark}-{1440x900,390x844}.png`. - Inbox: `compare-final-inbox-{light,dark}-{1440x900,390x844}.png`. - Sidebar mid-drag: `compare-final-sidebar-drag-{light,dark}-1440x900.png`. - Hosts list: `compare-final-hosts-list-{light,dark}-1440x900.png`. ## Visible differences - The shared shell geometry, Paper/Noir background treatment, display-serif page title, floating glass sidebar, icon row, menu surface, and mobile sidebar toggle align closely with the references. - Calternal shows calendar events, file rows, and its bottom mobile mode bar. Infraternal shows Dashboard status/host cards, the Hosts data table, and keeps Search/Inbox/Account in the mobile sidebar drawer. The dashboard cards are larger summary panels; the Hosts page uses a compact table header and data row rather than the reference's folder rows. - The menu contents and anchors differ: calternal's reference is a Files action menu; infraternal's is the page-title navigation menu. Their glass treatment and desktop sizing match; the mobile infraternal menu is slightly narrower because its labels are shorter. - Calternal's dialog is a centered share form on desktop and a tall mobile sheet. Infraternal's working inbox is a top-right glass panel on desktop and a shorter bottom sheet on mobile; contents and dimensions follow the inbox panel mapping. - During reorder, infraternal shows its custom group row and blue drop/focus outline. Calternal has no sidebar reordering; the file list is the closest row-treatment reference. - The reference Appearance settings screen has no target screenshot or route: the settings stub and its nav/account action were removed under the owner's rule against unbuilt UI. ## Removed unshipped surfaces Removed navigation/routes for Stacks, Images, Volumes, Terminals, Users & Roles, AI agent tokens, infraternal agents, Audit Log, the Settings stub, and the duplicate placeholder Inbox page. The working Inbox remains available from the sidebar. Removed Dashboard CPU, Memory and Disk “—” tiles and the fake Recent Activity/audit-log preview; also removed unsupported host telemetry, the fake inbox badge count, disabled SSH terminal action, and fake account Settings action. Audit Log returns with #38; Stacks, Images and Volumes return with #41 when those features ship.
Author
Owner

The corrected-artifact browser run passed the desktop route screenshots, including /hosts with the shell title, then failed the mobile sidebar drag assertion. The helper asserted aria-pressed=true immediately after touchStart, before sending any touchMove. Installed @dnd-kit/svelte is 0.5.0; its pointer sensor defaults touch to a 250ms activation delay with 5px tolerance, so the test needs to hold and issue an in-tolerance move before checking drag state. I’ll keep the assertion and adjust only its touch sequence.

The corrected-artifact browser run passed the desktop route screenshots, including `/hosts` with the shell title, then failed the mobile sidebar drag assertion. The helper asserted `aria-pressed=true` immediately after `touchStart`, before sending any `touchMove`. Installed `@dnd-kit/svelte` is 0.5.0; its pointer sensor defaults touch to a 250ms activation delay with 5px tolerance, so the test needs to hold and issue an in-tolerance move before checking drag state. I’ll keep the assertion and adjust only its touch sequence.
Author
Owner

Fast gate on port-c1 at f825a60:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Fast gate on `port-c1` at `f825a60`: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

C2 completion report

Branch: port-c2
Base: e12176d278
Head: 605f3d1e2c
Commits since the prior checkpoint: 9be04e1 (lazy target loading), 08d6df7 (immediate row state changes), 605f3d1 (shared dialog headings).

Implemented within C2 ownership:

  • Terminals keeps the paged GET /sessions list, lazy workspace/dialog chunks, tab/split/reattach path, close confirmation, target selection, and SSH handoff. Container and SSH inventory requests now start only when a terminal dialog or host-detail handoff needs them.
  • AI agent token list/create/revoke remains because the OpenAPI API exists.
  • Users and roles, and infraternal agents remain absent because there is no usable API for those pages in the OpenAPI contract. SSH host fingerprint trust remains on C1 host detail.
  • C2 keeps its empty-state terminal CTA because the shell currently does not render PageChrome.primary; the shell-owned integration is recorded for B.

Fast gate output on the final code, verbatim:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

Final browser gate output on 605f3d1, verbatim:

PASS browser: JavaScript dependencies
PASS browser: install Chromium and system dependencies
PASS browser: terminal fixture Playwright
PASS browser: build web app
PASS browser: build release binary
FAIL browser: Playwright against release server
curl: (7) Failed to connect to 127.0.0.1 port 29573 after 0 ms: Could not connect to server
METRIC container-detail JS gzip before terminal: 181081 bytes
METRIC container action focus: {"focused":true,"activeElement":"<button data-slot=\"button\" class=\"focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-md","disabled":false,"connected":true,"tabIndex":0,"display":"flex","visibility":"visible","rowKey":"h_01M3GX1TR6SDYVHAFXBRJ9VKJM/docker/3391bb810ae1425116e89c4283269849c7a4036022cc5847d4d6f5fdb5562050","visibilityState":"visible"}
FINDING browser: the shell did not render the Terminals page primary action from PageChrome
METRIC ai-agent-tokens route JS gzip: 121751 bytes
METRIC terminals route JS gzip: 122597 bytes
FINDING browser: raw terminal OPEN_OK metadata was session_id=present, replay_start=number, but the terminal pane did not persist its session ID
8583 | 
8584 | // packages/utils/stackTrace.ts
8585 | function captureRawStack() {
8586 |   const stackTraceLimit = Error.stackTraceLimit;
8587 |   Error.stackTraceLimit = 50;
8588 |   const error = new Error();
                           ^
error: expect(received).toMatch(expected)

Expected pattern: /^s_[0-9A-HJKMNP-TV-Z]{26}$/
Received string:  ""

Call Log:
- Timeout 10000ms exceeded while waiting on the predicate
 matcherResult: {
  pass: false,
  message: "expect(received).toMatch(expected)\n\nExpected pattern: /^s_[0-9A-HJKMNP-TV-Z]{26}$/\nReceived string:  \"\"\n\nCall Log:\n- Timeout 10000ms exceeded while waiting on the predicate",
  name: "toMatch",
},

      at captureRawStack (/home/kayg/wt/port-c2/node_modules/.bun/playwright-core@1.63.0/node_modules/playwright-core/lib/coreBundle.js:8588:21)
      at callMatcherAsStep (/home/kayg/wt/port-c2/node_modules/.bun/playwright@1.63.0/node_modules/playwright/lib/matchers/expect.js:13310:57)
      at openTerminalWorkspaceTab (/home/kayg/wt/port-c2/scripts/browser-check.mjs:1929:88)
      at checkSessionPagination (/home/kayg/wt/port-c2/scripts/browser-check.mjs:2108:24)
      at processTicksAndRejections (native:7:39)

Bun v1.4.2 (Linux x64)

The browser gate measured the terminal route at 122597 bytes gzip, 283 bytes below its 122880-byte cold-route cap; the AI agent token route is 121751 bytes. The gate cannot reach its populated-session pagination screenshot because the dev StreamClient drops session_id and replay_start from OPEN_OK. The raw frame had session_id present and replay_start numeric; the TerminalPane received no session ID. This parser fix is on #34 and outside C2 route ownership.

Screenshot artifacts refreshed by the final browser run:

List (these show the real empty state; the populated-list capture is blocked by the #34 parser issue):
/mnt/hdd/infraternal/artifacts/port-c2/light-1440x900-terminals-list.png
/mnt/hdd/infraternal/artifacts/port-c2/dark-1440x900-terminals-list.png
/mnt/hdd/infraternal/artifacts/port-c2/light-390x844-terminals-list.png
/mnt/hdd/infraternal/artifacts/port-c2/dark-390x844-terminals-list.png

Dialog:
/mnt/hdd/infraternal/artifacts/port-c2/light-1440x900-terminals-dialog.png
/mnt/hdd/infraternal/artifacts/port-c2/dark-1440x900-terminals-dialog.png
/mnt/hdd/infraternal/artifacts/port-c2/light-390x844-terminals-dialog.png
/mnt/hdd/infraternal/artifacts/port-c2/dark-390x844-terminals-dialog.png

Title menu:
/mnt/hdd/infraternal/artifacts/port-c2/light-1440x900-terminals-menu.png
/mnt/hdd/infraternal/artifacts/port-c2/dark-1440x900-terminals-menu.png
/mnt/hdd/infraternal/artifacts/port-c2/light-390x844-terminals-menu.png
/mnt/hdd/infraternal/artifacts/port-c2/dark-390x844-terminals-menu.png

Difference list against calternal:

  • The terminal session list follows calternal's full-width, unboxed row treatment with hover/selection tints. Its rows carry terminal target, kind, state, last-attached time, and open/close actions; the final screenshots show the honest empty state because the parser failure prevents a real session from reaching the list.
  • The dialog uses the shared DialogChrome, UIHeading, Pill, and SegmentedControl primitives, with exec/SSH target selectors and SSH trust guidance. It fits the 390px viewport without clipping; the calternal Share dialog is a different form and its reference has a narrow-width field overflow.
  • The shell title menu uses the copied menu surface and focus behavior, with Refresh sessions and Close active tab actions instead of calternal file actions.
  • Motion follows the repo's transform/opacity-only rule; session row state and hover tints change immediately. Dialog focus, Escape, restoration, labels, live loading/error status, and reduced motion remain in the flow.

Outstanding integration: merge the #34 stream parser fix to verify populated session pagination, reattach cursor behavior, and capture the populated list. The shell PageChrome.primary action remains a B-owned issue.

C2 completion report Branch: port-c2 Base: e12176d2781f38cee03d365977421e947a0b6a60 Head: 605f3d1e2c9bd33f9e8e226eb4d1f3e8604400ff Commits since the prior checkpoint: 9be04e1 (lazy target loading), 08d6df7 (immediate row state changes), 605f3d1 (shared dialog headings). Implemented within C2 ownership: - Terminals keeps the paged GET /sessions list, lazy workspace/dialog chunks, tab/split/reattach path, close confirmation, target selection, and SSH handoff. Container and SSH inventory requests now start only when a terminal dialog or host-detail handoff needs them. - AI agent token list/create/revoke remains because the OpenAPI API exists. - Users and roles, and infraternal agents remain absent because there is no usable API for those pages in the OpenAPI contract. SSH host fingerprint trust remains on C1 host detail. - C2 keeps its empty-state terminal CTA because the shell currently does not render PageChrome.primary; the shell-owned integration is recorded for B. Fast gate output on the final code, verbatim: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` Final browser gate output on 605f3d1, verbatim: ```text PASS browser: JavaScript dependencies PASS browser: install Chromium and system dependencies PASS browser: terminal fixture Playwright PASS browser: build web app PASS browser: build release binary FAIL browser: Playwright against release server curl: (7) Failed to connect to 127.0.0.1 port 29573 after 0 ms: Could not connect to server METRIC container-detail JS gzip before terminal: 181081 bytes METRIC container action focus: {"focused":true,"activeElement":"<button data-slot=\"button\" class=\"focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-md","disabled":false,"connected":true,"tabIndex":0,"display":"flex","visibility":"visible","rowKey":"h_01M3GX1TR6SDYVHAFXBRJ9VKJM/docker/3391bb810ae1425116e89c4283269849c7a4036022cc5847d4d6f5fdb5562050","visibilityState":"visible"} FINDING browser: the shell did not render the Terminals page primary action from PageChrome METRIC ai-agent-tokens route JS gzip: 121751 bytes METRIC terminals route JS gzip: 122597 bytes FINDING browser: raw terminal OPEN_OK metadata was session_id=present, replay_start=number, but the terminal pane did not persist its session ID 8583 | 8584 | // packages/utils/stackTrace.ts 8585 | function captureRawStack() { 8586 | const stackTraceLimit = Error.stackTraceLimit; 8587 | Error.stackTraceLimit = 50; 8588 | const error = new Error(); ^ error: expect(received).toMatch(expected) Expected pattern: /^s_[0-9A-HJKMNP-TV-Z]{26}$/ Received string: "" Call Log: - Timeout 10000ms exceeded while waiting on the predicate matcherResult: { pass: false, message: "expect(received).toMatch(expected)\n\nExpected pattern: /^s_[0-9A-HJKMNP-TV-Z]{26}$/\nReceived string: \"\"\n\nCall Log:\n- Timeout 10000ms exceeded while waiting on the predicate", name: "toMatch", }, at captureRawStack (/home/kayg/wt/port-c2/node_modules/.bun/playwright-core@1.63.0/node_modules/playwright-core/lib/coreBundle.js:8588:21) at callMatcherAsStep (/home/kayg/wt/port-c2/node_modules/.bun/playwright@1.63.0/node_modules/playwright/lib/matchers/expect.js:13310:57) at openTerminalWorkspaceTab (/home/kayg/wt/port-c2/scripts/browser-check.mjs:1929:88) at checkSessionPagination (/home/kayg/wt/port-c2/scripts/browser-check.mjs:2108:24) at processTicksAndRejections (native:7:39) Bun v1.4.2 (Linux x64) ``` The browser gate measured the terminal route at 122597 bytes gzip, 283 bytes below its 122880-byte cold-route cap; the AI agent token route is 121751 bytes. The gate cannot reach its populated-session pagination screenshot because the dev StreamClient drops session_id and replay_start from OPEN_OK. The raw frame had session_id present and replay_start numeric; the TerminalPane received no session ID. This parser fix is on #34 and outside C2 route ownership. Screenshot artifacts refreshed by the final browser run: List (these show the real empty state; the populated-list capture is blocked by the #34 parser issue): /mnt/hdd/infraternal/artifacts/port-c2/light-1440x900-terminals-list.png /mnt/hdd/infraternal/artifacts/port-c2/dark-1440x900-terminals-list.png /mnt/hdd/infraternal/artifacts/port-c2/light-390x844-terminals-list.png /mnt/hdd/infraternal/artifacts/port-c2/dark-390x844-terminals-list.png Dialog: /mnt/hdd/infraternal/artifacts/port-c2/light-1440x900-terminals-dialog.png /mnt/hdd/infraternal/artifacts/port-c2/dark-1440x900-terminals-dialog.png /mnt/hdd/infraternal/artifacts/port-c2/light-390x844-terminals-dialog.png /mnt/hdd/infraternal/artifacts/port-c2/dark-390x844-terminals-dialog.png Title menu: /mnt/hdd/infraternal/artifacts/port-c2/light-1440x900-terminals-menu.png /mnt/hdd/infraternal/artifacts/port-c2/dark-1440x900-terminals-menu.png /mnt/hdd/infraternal/artifacts/port-c2/light-390x844-terminals-menu.png /mnt/hdd/infraternal/artifacts/port-c2/dark-390x844-terminals-menu.png Difference list against calternal: - The terminal session list follows calternal's full-width, unboxed row treatment with hover/selection tints. Its rows carry terminal target, kind, state, last-attached time, and open/close actions; the final screenshots show the honest empty state because the parser failure prevents a real session from reaching the list. - The dialog uses the shared DialogChrome, UIHeading, Pill, and SegmentedControl primitives, with exec/SSH target selectors and SSH trust guidance. It fits the 390px viewport without clipping; the calternal Share dialog is a different form and its reference has a narrow-width field overflow. - The shell title menu uses the copied menu surface and focus behavior, with Refresh sessions and Close active tab actions instead of calternal file actions. - Motion follows the repo's transform/opacity-only rule; session row state and hover tints change immediately. Dialog focus, Escape, restoration, labels, live loading/error status, and reduced motion remain in the flow. Outstanding integration: merge the #34 stream parser fix to verify populated session pagination, reattach cursor behavior, and capture the populated list. The shell PageChrome.primary action remains a B-owned issue.
Author
Owner

The 300ms hold plus 1px in-tolerance move still left aria-pressed=false; browser event evidence showed the expected touch pointerdown and pointermove. I’m adjusting the synthetic move to 6px after the hold so it clears the sensor’s 5px movement threshold before retaining the same drag-start assertion.

The 300ms hold plus 1px in-tolerance move still left `aria-pressed=false`; browser event evidence showed the expected touch pointerdown and pointermove. I’m adjusting the synthetic move to 6px after the hold so it clears the sensor’s 5px movement threshold before retaining the same drag-start assertion.
Author
Owner

Fast gate on port-c1 at 8e45f4b:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Fast gate on `port-c1` at `8e45f4b`: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Fast gate on port-c1 at 7c27d97:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Fast gate on `port-c1` at `7c27d97`: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

C1 visual comparison finding: the infrastructure resource rows still had an opaque fill and rounded box treatment unlike the calternal reference list, whose rows are full-width and tinted on hover/selection. Changed the shared route-local list to a transparent baseline with hover and keyboard-focus tints. Commit: 3e4d871528.

scripts/verify fast output on this head:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

Browser gate is running; artifacts are directed to /mnt/hdd/infraternal/artifacts/port-c1.

C1 visual comparison finding: the infrastructure resource rows still had an opaque fill and rounded box treatment unlike the calternal reference list, whose rows are full-width and tinted on hover/selection. Changed the shared route-local list to a transparent baseline with hover and keyboard-focus tints. Commit: 3e4d8715287dbcd248c24eeaf978bcbb1d8657cf. `scripts/verify fast` output on this head: ``` PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` Browser gate is running; artifacts are directed to `/mnt/hdd/infraternal/artifacts/port-c1`.
Author
Owner

C1 implementation is complete on branch port-c1.

Head: a80361ebd3dadd311b0b61c924292e6024d20975

scripts/verify fast output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

scripts/verify browser output:

PASS browser: JavaScript dependencies
PASS browser: install Chromium and system dependencies
PASS browser: terminal fixture Playwright
PASS browser: build web app
PASS browser: build release binary
FAIL browser: Playwright against release server

The browser run captured all light/dark desktop/mobile route artifacts and passed the cold container-detail budget at 122,873 bytes (limit 122,880), terminal DATA/CREDIT accounting, Ghostty color checks, and topbar/inbox scroll smoke checks. It then failed in the existing shared-shell mobile drawer touch-reorder check:

Expected: "true"
Received: "false"

The browser recorded trusted touch pointerdown, touchstart, and pointermove events at the drag handle with touch-action: none; the shell’s aria-pressed state stayed false. The assertion remains enabled. Shell code is outside C1 ownership.

Screenshots are under /mnt/hdd/infraternal/artifacts/port-c1/:

  • Dashboard: light-1440x900-dashboard.png, dark-1440x900-dashboard.png, light-390x844-dashboard.png, dark-390x844-dashboard.png.
  • Hosts: light-1440x900-hosts.png, dark-1440x900-hosts.png, light-390x844-hosts.png, dark-390x844-hosts.png.
  • Host detail: light-1440x900-host-detail.png, dark-1440x900-host-detail.png, light-390x844-host-detail.png, dark-390x844-host-detail.png.
  • Containers: light-1440x900-containers.png, dark-1440x900-containers.png, light-390x844-containers.png, dark-390x844-containers.png.
  • Container detail and runtime: light-1440x900-container-detail.png, dark-1440x900-container-detail.png, light-390x844-container-detail.png, dark-390x844-container-detail.png, and matching *-container-detail-runtime.png files.
  • Device review: device-light-1440x900.png, device-dark-1440x900.png, device-light-390x844.png, device-dark-390x844.png.

Differences against calternal’s references:

  • C1 lists use full-width transparent rows with separators and hover/focus tint, while retaining infrastructure-specific status indicators, engine/host/image columns and lifecycle actions.
  • The dashboard presents live host/container/engine counts and current attention state instead of file-list content; blank CPU/memory/disk tiles and placeholder activity are removed.
  • At phone width, lower-priority host/container columns are hidden, filters collapse behind the Filters control, and row actions use a compact menu.
  • The Workspace/Infrastructure navigation follows infraternal routes; calternal’s reference shell shows Files/Shared/Recent navigation and a bottom dock.
C1 implementation is complete on branch `port-c1`. Head: `a80361ebd3dadd311b0b61c924292e6024d20975` `scripts/verify fast` output: ``` PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` `scripts/verify browser` output: ``` PASS browser: JavaScript dependencies PASS browser: install Chromium and system dependencies PASS browser: terminal fixture Playwright PASS browser: build web app PASS browser: build release binary FAIL browser: Playwright against release server ``` The browser run captured all light/dark desktop/mobile route artifacts and passed the cold container-detail budget at 122,873 bytes (limit 122,880), terminal DATA/CREDIT accounting, Ghostty color checks, and topbar/inbox scroll smoke checks. It then failed in the existing shared-shell mobile drawer touch-reorder check: ``` Expected: "true" Received: "false" ``` The browser recorded trusted touch `pointerdown`, `touchstart`, and `pointermove` events at the drag handle with `touch-action: none`; the shell’s `aria-pressed` state stayed false. The assertion remains enabled. Shell code is outside C1 ownership. Screenshots are under `/mnt/hdd/infraternal/artifacts/port-c1/`: - Dashboard: `light-1440x900-dashboard.png`, `dark-1440x900-dashboard.png`, `light-390x844-dashboard.png`, `dark-390x844-dashboard.png`. - Hosts: `light-1440x900-hosts.png`, `dark-1440x900-hosts.png`, `light-390x844-hosts.png`, `dark-390x844-hosts.png`. - Host detail: `light-1440x900-host-detail.png`, `dark-1440x900-host-detail.png`, `light-390x844-host-detail.png`, `dark-390x844-host-detail.png`. - Containers: `light-1440x900-containers.png`, `dark-1440x900-containers.png`, `light-390x844-containers.png`, `dark-390x844-containers.png`. - Container detail and runtime: `light-1440x900-container-detail.png`, `dark-1440x900-container-detail.png`, `light-390x844-container-detail.png`, `dark-390x844-container-detail.png`, and matching `*-container-detail-runtime.png` files. - Device review: `device-light-1440x900.png`, `device-dark-1440x900.png`, `device-light-390x844.png`, `device-dark-390x844.png`. Differences against calternal’s references: - C1 lists use full-width transparent rows with separators and hover/focus tint, while retaining infrastructure-specific status indicators, engine/host/image columns and lifecycle actions. - The dashboard presents live host/container/engine counts and current attention state instead of file-list content; blank CPU/memory/disk tiles and placeholder activity are removed. - At phone width, lower-priority host/container columns are hidden, filters collapse behind the Filters control, and row actions use a compact menu. - The Workspace/Infrastructure navigation follows infraternal routes; calternal’s reference shell shows Files/Shared/Recent navigation and a bottom dock.
Author
Owner

Started port-final on branch calternal-port at base head 7338b01ba9856ed376ba5cde5d3aa76691518ea2.

I reviewed the complete #46 thread and the required repo/design docs. I’m integrating port-c1, port-c2, and port-c3, then origin/dev, carrying forward the preview merge resolutions before removing shadcn and fixing the listed behavior and budgets. The pinned calternal source remains read-only.

Started port-final on branch `calternal-port` at base head `7338b01ba9856ed376ba5cde5d3aa76691518ea2`. I reviewed the complete #46 thread and the required repo/design docs. I’m integrating `port-c1`, `port-c2`, and `port-c3`, then `origin/dev`, carrying forward the preview merge resolutions before removing shadcn and fixing the listed behavior and budgets. The pinned calternal source remains read-only.
Author
Owner

C1 is integrated on calternal-port in merge commit 3f7c904.

The scripts/browser-check.mjs conflict keeps the shell-owned Hosts title assertion, the mobile Notifications path through the sidebar sheet, and C1's touch hold/move sequence after touchstart. This combines both lane behaviors and carries the prior preview resolution for the shell-title path. node --check scripts/browser-check.mjs and git diff --check passed before the merge commit.

C1 is integrated on `calternal-port` in merge commit `3f7c904`. The `scripts/browser-check.mjs` conflict keeps the shell-owned Hosts title assertion, the mobile Notifications path through the sidebar sheet, and C1's touch hold/move sequence after touchstart. This combines both lane behaviors and carries the prior preview resolution for the shell-title path. `node --check scripts/browser-check.mjs` and `git diff --check` passed before the merge commit.
Author
Owner

C2 is integrated on calternal-port in merge commit 9b2bf51.

The scripts/browser-check.mjs resolution keeps C2's route-aware title assertions and owned browser-resource cleanup, while retaining the shell lane's deferred mobile keyboard pass and shell-title focus check. This follows the prior preview resolution pattern. node --check scripts/browser-check.mjs and git diff --check passed before the merge commit.

C2 is integrated on `calternal-port` in merge commit `9b2bf51`. The `scripts/browser-check.mjs` resolution keeps C2's route-aware title assertions and owned browser-resource cleanup, while retaining the shell lane's deferred mobile keyboard pass and shell-title focus check. This follows the prior preview resolution pattern. `node --check scripts/browser-check.mjs` and `git diff --check` passed before the merge commit.
Author
Owner

C3 is integrated on calternal-port in merge commit 2590c9d.

The route matrix now includes /settings alongside Terminals and AI agent tokens. I retained C2's route-aware title helper and C3's viewport-sized Settings screenshots, Settings title-menu navigation, and no-placeholder route checks. The removed-navigation assertion continues to exclude only unshipped pages. node --check scripts/browser-check.mjs and git diff --check passed before the merge commit.

C3 is integrated on `calternal-port` in merge commit `2590c9d`. The route matrix now includes `/settings` alongside Terminals and AI agent tokens. I retained C2's route-aware title helper and C3's viewport-sized Settings screenshots, Settings title-menu navigation, and no-placeholder route checks. The removed-navigation assertion continues to exclude only unshipped pages. `node --check scripts/browser-check.mjs` and `git diff --check` passed before the merge commit.
Author
Owner

Integrated the three port lanes and the fetched origin/dev head (f640461). Resolved the shared shell conflicts using the prior preview merge’s decisions: the shell/docs follow calternal, Sidebar.svelte retains dev sidebar persistence, and browser coverage retains both calternal settings/route checks and dev persistence/auth checks. Cherry-picked the PREVIEW_REF override for scripts/preview (bb2afd7). Merge commits are 3f7c904, 9b2bf51, 2590c9d, and 0122c98.

Integrated the three port lanes and the fetched `origin/dev` head (`f640461`). Resolved the shared shell conflicts using the prior preview merge’s decisions: the shell/docs follow calternal, `Sidebar.svelte` retains dev sidebar persistence, and browser coverage retains both calternal settings/route checks and dev persistence/auth checks. Cherry-picked the `PREVIEW_REF` override for `scripts/preview` (`bb2afd7`). Merge commits are `3f7c904`, `9b2bf51`, `2590c9d`, and `0122c98`.
Author
Owner

OPEN_OK replay metadata fix at e8d01a6: added typed replay_start parsing and validation to the stream client. The new unit test first reproduced the loss (expected replay_start: 96, received no field); after the fix, all 70 stream tests pass. TerminalPane now reads the typed value, stores it with session_id and the consumed cursor in the workspace state, and uses those saved values to reattach. Verification: bun --cwd=packages/stream run test — 70 passed; bun --cwd=packages/stream run check — passed; bun --cwd=packages/web run check — 0 errors, 1 pre-existing unused CSS selector warning; bun --cwd=packages/web run test -- src/routes/terminals/lib/terminal-replay.test.ts — 3 passed.

OPEN_OK replay metadata fix at `e8d01a6`: added typed `replay_start` parsing and validation to the stream client. The new unit test first reproduced the loss (expected `replay_start: 96`, received no field); after the fix, all 70 stream tests pass. TerminalPane now reads the typed value, stores it with `session_id` and the consumed cursor in the workspace state, and uses those saved values to reattach. Verification: `bun --cwd=packages/stream run test` — 70 passed; `bun --cwd=packages/stream run check` — passed; `bun --cwd=packages/web run check` — 0 errors, 1 pre-existing unused CSS selector warning; `bun --cwd=packages/web run test -- src/routes/terminals/lib/terminal-replay.test.ts` — 3 passed.
Author
Owner

Lane D slice committed: c0f93b1 (Remove shadcn layer and use calternal UI).

The generated packages/ui/src/lib/components/ui tree and obsolete wrapper primitives are deleted. Removed shadcn-svelte, bits-ui, tailwind-variants, cn, tw-animate-css, Tailwind-only plugin/configuration and generated CSS aliases; bun.lock was regenerated. Retained dnd-kit, Svelte virtualization, Lucide and svelte-sonner. docs/UI.md now describes calternal's system.

Gate finding: the first scripts/verify fast run failed the pre-existing global allocator probe in crates/engine because the default parallel Rust test harness counted other unit-test allocations (136 vs the test's <100 bound). The probe passed alone and the engine suite passed with --test-threads=1. A second unmodified scripts/verify fast run passed every step. Exact output is being retained for the final report.

Next: enforce cold gzip on every shipped route, capture missing detail/device/touch screenshots, then run integration and browser gates after checking load and competing gate processes.

Lane D slice committed: c0f93b1 (Remove shadcn layer and use calternal UI). The generated packages/ui/src/lib/components/ui tree and obsolete wrapper primitives are deleted. Removed shadcn-svelte, bits-ui, tailwind-variants, cn, tw-animate-css, Tailwind-only plugin/configuration and generated CSS aliases; bun.lock was regenerated. Retained dnd-kit, Svelte virtualization, Lucide and svelte-sonner. docs/UI.md now describes calternal's system. Gate finding: the first scripts/verify fast run failed the pre-existing global allocator probe in crates/engine because the default parallel Rust test harness counted other unit-test allocations (136 vs the test's <100 bound). The probe passed alone and the engine suite passed with --test-threads=1. A second unmodified scripts/verify fast run passed every step. Exact output is being retained for the final report. Next: enforce cold gzip on every shipped route, capture missing detail/device/touch screenshots, then run integration and browser gates after checking load and competing gate processes.
Author
Owner

Browser evidence: the first port-final browser run passed preflight and release build, then timed out at captureAuthScreenshots because the harness still queried “Sign in” as a tab. The calternal SegmentedControl correctly exposes this mode picker as radiogroup/radio with aria-checked. Updated all five auth flows to select the radio and assert it is checked; node --check scripts/browser-check.mjs passed. Waiting for the active shared integration gate before rerunning browser.

Browser evidence: the first port-final browser run passed preflight and release build, then timed out at `captureAuthScreenshots` because the harness still queried “Sign in” as a `tab`. The calternal `SegmentedControl` correctly exposes this mode picker as `radiogroup`/`radio` with `aria-checked`. Updated all five auth flows to select the radio and assert it is checked; `node --check scripts/browser-check.mjs` passed. Waiting for the active shared integration gate before rerunning browser.
Author
Owner

Browser gate finding: the attempt at 15:30 passed JavaScript dependency setup and Chromium install, then the terminal fixture failed to bind its default 127.0.0.1:4175 because a transient Node listener was present. The listener disappeared during read-only owner checks; no process was stopped or signaled. The terminal Playwright and Vite configs support INFRATERMINAL_TERMINAL_TEST_PORT; the retry will use free port 18338 after the currently active browser gate clears.

Browser gate finding: the attempt at 15:30 passed JavaScript dependency setup and Chromium install, then the terminal fixture failed to bind its default `127.0.0.1:4175` because a transient Node listener was present. The listener disappeared during read-only owner checks; no process was stopped or signaled. The terminal Playwright and Vite configs support `INFRATERMINAL_TERMINAL_TEST_PORT`; the retry will use free port 18338 after the currently active browser gate clears.
Author
Owner

Browser evidence: port-specific fixture Playwright and the release build passed. The browser run then stopped in the unsupported multi-tab fallback because it waited for a Containers <h1>. packages/web/src/routes/containers/+page.svelte has no content h1; usePageChrome renders the route title in .mode-header .mh-title. Updated the owned-route title helper and all three direct Containers title checks to use the shared shell title (Dashboard still checks its content heading). node --check scripts/browser-check.mjs and git diff --check pass. The next run will use the correctly spelled INFRATERNAL_ARTIFACT_DIR, a fresh artifact folder, and free fixture port 18339.

Browser evidence: port-specific fixture Playwright and the release build passed. The browser run then stopped in the unsupported multi-tab fallback because it waited for a Containers `<h1>`. `packages/web/src/routes/containers/+page.svelte` has no content `h1`; `usePageChrome` renders the route title in `.mode-header .mh-title`. Updated the owned-route title helper and all three direct Containers title checks to use the shared shell title (Dashboard still checks its content heading). `node --check scripts/browser-check.mjs` and `git diff --check` pass. The next run will use the correctly spelled `INFRATERNAL_ARTIFACT_DIR`, a fresh artifact folder, and free fixture port 18339.
Author
Owner

Browser progress: after the shared-shell-title correction, both locks-only and neither multi-tab fallback checks passed, including stale-access recovery. The next failure was in checkSidebarPersistence: the preceding settings screenshot loop leaves the page at 390×844, but this test performs desktop mouse sorting and hovered the hidden mobile sidebar (.app-sidebar-mobile[hidden]). Updated the helper to set a 1440×900 viewport and scope all of its sidebar locators to .sidebar-layout > .app-sidebar. node --check and git diff --check pass. Waiting for the active browser gate before retrying.

Browser progress: after the shared-shell-title correction, both `locks-only` and `neither` multi-tab fallback checks passed, including stale-access recovery. The next failure was in `checkSidebarPersistence`: the preceding settings screenshot loop leaves the page at 390×844, but this test performs desktop mouse sorting and hovered the hidden mobile sidebar (`.app-sidebar-mobile[hidden]`). Updated the helper to set a 1440×900 viewport and scope all of its sidebar locators to `.sidebar-layout > .app-sidebar`. `node --check` and `git diff --check` pass. Waiting for the active browser gate before retrying.
Author
Owner

Browser progress: the shared-title and explicit-desktop-viewport fixes worked; the fallback multi-tab checks passed. The persistence test then failed because its expected Infrastructure order still included Stacks, Images and Volumes. packages/web/src/lib/shell/navigation.svelte.ts confirms the shipped default group contains only Hosts and Containers, matching the no-unbuilt-UI rule. Updated persistence, reset and mobile reorder assertions to use a shared DEFAULT_INFRASTRUCTURE_ITEMS list. node --check scripts/browser-check.mjs and git diff --check pass. Waiting for the next browser slot.

Browser progress: the shared-title and explicit-desktop-viewport fixes worked; the fallback multi-tab checks passed. The persistence test then failed because its expected Infrastructure order still included Stacks, Images and Volumes. `packages/web/src/lib/shell/navigation.svelte.ts` confirms the shipped default group contains only Hosts and Containers, matching the no-unbuilt-UI rule. Updated persistence, reset and mobile reorder assertions to use a shared `DEFAULT_INFRASTRUCTURE_ITEMS` list. `node --check scripts/browser-check.mjs` and `git diff --check` pass. Waiting for the next browser slot.
Author
Owner

Found the 422 source in the real browser run: /api/v1/me/sidebar validates the complete stable-ID set (12 IDs), while the calternal port correctly renders only built routes and had serialized only those visible IDs. Added a regression test that first failed with six missing IDs and then passed after the fix. Sidebar persistence now carries unavailable server IDs through saves in their existing groups/slots; those IDs remain absent from rendered navigation.

Found the 422 source in the real browser run: `/api/v1/me/sidebar` validates the complete stable-ID set (12 IDs), while the calternal port correctly renders only built routes and had serialized only those visible IDs. Added a regression test that first failed with six missing IDs and then passed after the fix. Sidebar persistence now carries unavailable server IDs through saves in their existing groups/slots; those IDs remain absent from rendered navigation.
Author
Owner

The route remained over budget at 8aadf9e: 121,728 gzip bytes versus the 117,760-byte target, only 68 bytes below the preceding run. A browser assertion failed against the old page because Open logs was absent and the log panel was already rendered. Commit b09c644 moves log streaming, controls and the virtualized output into an on-demand component; the browser check now measures before opening it, then verifies the opened viewer. Budget measurement and browser verification are pending.

The route remained over budget at `8aadf9e`: 121,728 gzip bytes versus the 117,760-byte target, only 68 bytes below the preceding run. A browser assertion failed against the old page because `Open logs` was absent and the log panel was already rendered. Commit `b09c644` moves log streaming, controls and the virtualized output into an on-demand component; the browser check now measures before opening it, then verifies the opened viewer. Budget measurement and browser verification are pending.
Author
Owner

Browser run 18345 confirmed the viewer is absent from the cold route and loads after “Open logs”. Cold detail JavaScript fell from 121,728 to 118,705 gzip bytes, but the required maximum is 117,760; the gate stopped 945 bytes over budget before route screenshots. Sidebar persistence passed in this run. I’m tracing the remaining detail-page imports before the next measurement.

Browser run `18345` confirmed the viewer is absent from the cold route and loads after “Open logs”. Cold detail JavaScript fell from 121,728 to 118,705 gzip bytes, but the required maximum is 117,760; the gate stopped 945 bytes over budget before route screenshots. Sidebar persistence passed in this run. I’m tracing the remaining detail-page imports before the next measurement.
Author
Owner

The 18346 browser measurement passes: cold container detail is 117,637 gzip bytes, under the 117,760-byte limit (5,243 bytes below the 122,880-byte route cap). The terminal transport is now loaded only for an opened log/terminal surface. “Jump to latest” passed. The run next reached two stale browser call sites that expected logs on a fresh detail navigation; commit 87cc070 makes those flows explicitly open the viewer. Full browser verification is rerunning.

The 18346 browser measurement passes: cold container detail is 117,637 gzip bytes, under the 117,760-byte limit (5,243 bytes below the 122,880-byte route cap). The terminal transport is now loaded only for an opened log/terminal surface. “Jump to latest” passed. The run next reached two stale browser call sites that expected logs on a fresh detail navigation; commit `87cc070` makes those flows explicitly open the viewer. Full browser verification is rerunning.
Author
Owner

Browser run 18347 repeats the passing cold-detail measurement at 117,637 gzip bytes, then reaches the Terminals route. usePageChrome declares a New terminal primary action, but the rendered shell exposes only Refresh sessions and Split active tab; when a persistent session exists the empty-state “Open a terminal” action is absent too. The browser check cannot create the next exec pane. The same catch emitted an OPEN_OK persistence finding based on the last observed frame, so I’m checking that path after restoring an actual create action rather than treating that diagnostic as confirmed evidence.

Browser run `18347` repeats the passing cold-detail measurement at 117,637 gzip bytes, then reaches the Terminals route. `usePageChrome` declares a `New terminal` primary action, but the rendered shell exposes only `Refresh sessions` and `Split active tab`; when a persistent session exists the empty-state “Open a terminal” action is absent too. The browser check cannot create the next exec pane. The same catch emitted an OPEN_OK persistence finding based on the last observed frame, so I’m checking that path after restoring an actual create action rather than treating that diagnostic as confirmed evidence.
Author
Owner

Root cause of the Terminals dead end: PageChrome.primary was declared and the calternal PrimaryPill primitive existed, but ModeHeader never rendered it. Commit 6235981 wires the shared pill beside page tools, documents its use, and asserts the accessible “New terminal” action while sessions already exist. The 18347 OPEN_OK finding was a false positive from an earlier unrelated frame; commit 71f7ce3 correlates the matching OPEN and OPEN_OK to a newly mounted pane before reporting a persistence issue. scripts/verify fast passed all 16 checks after the primary-action fix; browser verification is rerunning.

Root cause of the Terminals dead end: `PageChrome.primary` was declared and the calternal `PrimaryPill` primitive existed, but `ModeHeader` never rendered it. Commit `6235981` wires the shared pill beside page tools, documents its use, and asserts the accessible “New terminal” action while sessions already exist. The `18347` OPEN_OK finding was a false positive from an earlier unrelated frame; commit `71f7ce3` correlates the matching OPEN and OPEN_OK to a newly mounted pane before reporting a persistence issue. `scripts/verify fast` passed all 16 checks after the primary-action fix; browser verification is rerunning.
Author
Owner

Run 18348 showed that a static PrimaryPill import raised cold container-detail gzip to 117,988 bytes, 228 bytes over the 117,760-byte threshold. Commit 50d822e keeps the same shared primary pill but dynamically loads it only when a page declares a primary action. The Terminals action stays live while routes without one avoid its code. Fast verification passed all 16 checks; the browser gate will confirm both budget and action.

Run `18348` showed that a static `PrimaryPill` import raised cold container-detail gzip to 117,988 bytes, 228 bytes over the 117,760-byte threshold. Commit `50d822e` keeps the same shared primary pill but dynamically loads it only when a page declares a primary action. The Terminals action stays live while routes without one avoid its code. Fast verification passed all 16 checks; the browser gate will confirm both budget and action.
Author
Owner

The 18349 run measured 119,710 bytes after the conditional primary pill change. Chunk inspection found the 6.2 KiB @infraternal/stream module was still statically included solely for a terminal-only StreamOpenError instanceof check. That was the remaining eager dependency; it is now dynamically imported with the terminal attachment. The conditional PrimaryPill experiment was reverted because its shell chunk was preloaded; the shared static component had cost only 351 bytes. Fast gate and a fresh browser measurement are pending.

The 18349 run measured 119,710 bytes after the conditional primary pill change. Chunk inspection found the 6.2 KiB `@infraternal/stream` module was still statically included solely for a terminal-only `StreamOpenError` `instanceof` check. That was the remaining eager dependency; it is now dynamically imported with the terminal attachment. The conditional `PrimaryPill` experiment was reverted because its shell chunk was preloaded; the shared static component had cost only 351 bytes. Fast gate and a fresh browser measurement are pending.
Author
Owner

Run 18350 passed the cold detail budget at 111,965 gzip bytes, 10,915 bytes under the 122,880-byte cap. Sidebar drag/reload/two-context persistence and both “Jump to latest” checks passed. The run reached AI-token dialog capture and found an ambiguous locator because the newly rendered shell primary and existing empty-state CTA share a label. Commit ecc1e15 scopes shell-primary interactions and separately verifies the contextual CTA. Browser verification is rerunning; the Terminals pane flow remains ahead.

Run `18350` passed the cold detail budget at 111,965 gzip bytes, 10,915 bytes under the 122,880-byte cap. Sidebar drag/reload/two-context persistence and both “Jump to latest” checks passed. The run reached AI-token dialog capture and found an ambiguous locator because the newly rendered shell primary and existing empty-state CTA share a label. Commit `ecc1e15` scopes shell-primary interactions and separately verifies the contextual CTA. Browser verification is rerunning; the Terminals pane flow remains ahead.
Author
Owner

Browser evidence on ecc1e15: the latest browser run measured container detail at 111,965 gzip bytes and confirmed a newly opened terminal pane received its correlated persistent OPEN_OK.session_id. It then stopped because the pagination harness found multiple same-label close buttons. I changed the harness to map the active workspace tab ID to its corresponding close action; node --check scripts/browser-check.mjs and git diff --check pass. I will rerun the browser gate on a fresh fixture port.

Browser evidence on `ecc1e15`: the latest browser run measured container detail at 111,965 gzip bytes and confirmed a newly opened terminal pane received its correlated persistent `OPEN_OK.session_id`. It then stopped because the pagination harness found multiple same-label close buttons. I changed the harness to map the active workspace tab ID to its corresponding close action; `node --check scripts/browser-check.mjs` and `git diff --check` pass. I will rerun the browser gate on a fresh fixture port.
Author
Owner

Browser run 18352 passed the route budget checks (container detail 111,965 gzip; AI agent tokens 107,695; Terminals 108,509) and reached persistent-session pagination. The first close-locator fix selected the owning active tab, but the test incorrectly required the entire workspace to become empty; one remaining pane was present. The harness now maps the newly returned pane to its own aria-controls tab and checks that this pane's session_id disappears before asserting server-side detached state. node --check scripts/browser-check.mjs and git diff --check pass; the browser gate will verify the revised flow.

Browser run `18352` passed the route budget checks (container detail 111,965 gzip; AI agent tokens 107,695; Terminals 108,509) and reached persistent-session pagination. The first close-locator fix selected the owning active tab, but the test incorrectly required the entire workspace to become empty; one remaining pane was present. The harness now maps the newly returned pane to its own `aria-controls` tab and checks that this pane's `session_id` disappears before asserting server-side `detached` state. `node --check scripts/browser-check.mjs` and `git diff --check` pass; the browser gate will verify the revised flow.
Author
Owner

Browser run 18353 passed the targeted-pane close check, then the pagination setup found “Open in new tab” disabled. The harness had cleared local storage but navigated to the same Terminals route without explicitly reloading the current workspace component. It now reloads after clearing the workspace key and asserts zero mounted panes before creating pagination sessions. The browser run had already confirmed route gzip values of 111,965 B (container detail), 107,695 B (AI agent tokens), and 108,509 B (Terminals); Jump to latest passed.

Browser run `18353` passed the targeted-pane close check, then the pagination setup found “Open in new tab” disabled. The harness had cleared local storage but navigated to the same Terminals route without explicitly reloading the current workspace component. It now reloads after clearing the workspace key and asserts zero mounted panes before creating pagination sessions. The browser run had already confirmed route gzip values of 111,965 B (container detail), 107,695 B (AI agent tokens), and 108,509 B (Terminals); `Jump to latest` passed.
Author
Owner

Browser run 18354 measured the same route budgets and passed Jump to latest, but revealed that pagination runs after the AI agent tokens measurement: reloading the current page therefore stayed on AI agent tokens and failed the Terminals title assertion. The setup now navigates to Containers, then Terminals, after removing the saved workspace, so the terminal workspace mounts fresh; it asserts the pane list is empty before pagination. node --check and git diff --check pass.

Browser run `18354` measured the same route budgets and passed `Jump to latest`, but revealed that pagination runs after the AI agent tokens measurement: reloading the current page therefore stayed on AI agent tokens and failed the Terminals title assertion. The setup now navigates to Containers, then Terminals, after removing the saved workspace, so the terminal workspace mounts fresh; it asserts the pane list is empty before pagination. `node --check` and `git diff --check` pass.
Author
Owner

Browser run 18355 passed route capture and found the pagination “Open in new tab” control disabled. The workspace component persists its tab state from a reactive effect, so clearing localStorage before navigating away could be overwritten during unmount and restore the old full workspace. The harness now navigates away first, clears the key after the Terminals component is unmounted, then returns and asserts zero panes. Jump to latest and the measured route gzip values still passed (111,965 / 107,695 / 108,509 B for detail / tokens / Terminals).

Browser run `18355` passed route capture and found the pagination “Open in new tab” control disabled. The workspace component persists its tab state from a reactive effect, so clearing `localStorage` before navigating away could be overwritten during unmount and restore the old full workspace. The harness now navigates away first, clears the key after the Terminals component is unmounted, then returns and asserts zero panes. `Jump to latest` and the measured route gzip values still passed (111,965 / 107,695 / 108,509 B for detail / tokens / Terminals).
Author
Owner

Browser run 18356 again reached the pagination dialog with “Open in new tab” disabled despite navigating away before clearing storage. I added an explicit assertion that the fresh workspace has no tab close controls and a bounded diagnostic reporting only whether targets are loading/failed, whether the workspace is full, tab counts, and whether a target selection exists. This will distinguish stale workspace state from a target-load or selection issue on the next browser run. The run continued to pass route budgets and Jump to latest.

Browser run `18356` again reached the pagination dialog with “Open in new tab” disabled despite navigating away before clearing storage. I added an explicit assertion that the fresh workspace has no tab close controls and a bounded diagnostic reporting only whether targets are loading/failed, whether the workspace is full, tab counts, and whether a target selection exists. This will distinguish stale workspace state from a target-load or selection issue on the next browser run. The run continued to pass route budgets and `Jump to latest`.
Author
Owner

The diagnostic browser run 18357 showed the disabled control was the workspace limit: target loading/error were both false and a target was selected, while the DOM and saved workspace each contained 8 tabs. This means pagination was accumulating tabs; same-label close buttons plus positional mapping were not a safe target after the segmented tab list changed shape. I added data-workspace-tab-close-id to each shared close control, have the test close the exact tab containing the created pane, and assert the workspace tab list returns to zero before creating the next session.

The diagnostic browser run `18357` showed the disabled control was the workspace limit: target loading/error were both false and a target was selected, while the DOM and saved workspace each contained 8 tabs. This means pagination was accumulating tabs; same-label close buttons plus positional mapping were not a safe target after the segmented tab list changed shape. I added `data-workspace-tab-close-id` to each shared close control, have the test close the exact tab containing the created pane, and assert the workspace tab list returns to zero before creating the next session.
Author
Owner

Browser run 18358 passed the earlier target diagnostics and selected the newly opened tab’s exact close control by data-workspace-tab-close-id. The click returned, but that tab remained in the DOM for 10 seconds, so the assertion now exposes a real close-path issue or an immediate restore. I’m adding a post-click snapshot of the button/tab/pane counts, active tab ID and saved tab count before adjusting product behavior. Route budgets passed (container detail 111,964 B; AI agent tokens 107,694 B; Terminals 108,508 B) and Jump to latest passed.

Browser run `18358` passed the earlier target diagnostics and selected the newly opened tab’s exact close control by `data-workspace-tab-close-id`. The click returned, but that tab remained in the DOM for 10 seconds, so the assertion now exposes a real close-path issue or an immediate restore. I’m adding a post-click snapshot of the button/tab/pane counts, active tab ID and saved tab count before adjusting product behavior. Route budgets passed (container detail 111,964 B; AI agent tokens 107,694 B; Terminals 108,508 B) and `Jump to latest` passed.
Author
Owner

The 18359 post-click snapshot showed the tab remained mounted, its terminal pane was gone, its selected state had cleared, and the saved workspace still held one tab. The listener attached directly to the original button did not observe a click, though the Playwright locator action returned; the control may have been replaced between observation and activation. I replaced that with a document-level capture listener and added a hit-target check (connected/disabled/center hit), so the next run can distinguish a missed pointer target from a workspace state problem.

The `18359` post-click snapshot showed the tab remained mounted, its terminal pane was gone, its selected state had cleared, and the saved workspace still held one tab. The listener attached directly to the original button did not observe a click, though the Playwright locator action returned; the control may have been replaced between observation and activation. I replaced that with a document-level capture listener and added a hit-target check (connected/disabled/center hit), so the next run can distinguish a missed pointer target from a workspace state problem.
Author
Owner

Browser run 18360 confirmed the close pointer hit the intended enabled 30×30 control and bubbled a click; afterward the terminal pane disappeared, but the workspace still contained one inactive tab and did not persist the expected removal. To keep the real 51-session pagination flow deterministic while testing a documented workspace action, the harness now focuses the tab owning the pane and uses its supported Ctrl+Shift+W shortcut, then asserts the pane and workspace controls are gone before checking server-side detachment. I removed the temporary close-control data attribute and pointer diagnostics. The close-control discrepancy remains under investigation separately; the rest of the UI has not been changed based on this harness observation.

Browser run `18360` confirmed the close pointer hit the intended enabled 30×30 control and bubbled a click; afterward the terminal pane disappeared, but the workspace still contained one inactive tab and did not persist the expected removal. To keep the real 51-session pagination flow deterministic while testing a documented workspace action, the harness now focuses the tab owning the pane and uses its supported `Ctrl+Shift+W` shortcut, then asserts the pane and workspace controls are gone before checking server-side detachment. I removed the temporary close-control data attribute and pointer diagnostics. The close-control discrepancy remains under investigation separately; the rest of the UI has not been changed based on this harness observation.
Author
Owner

Browser run 18361 again showed one tab after the shortcut removed the terminal pane. This indicates the pagination page was restoring an older tab from origin storage; its first empty-DOM checks can run before the lazy workspace import finishes. I now unmount the main page from Terminals before clearing the shared workspace key, assert the active pane-owned tab ID disappears after Ctrl+Shift+W, then restore the main page URL. node --check and git diff --check pass. The prior run still measured container detail 111,965 B, AI agent tokens 107,695 B, Terminals 108,509 B, and passed Jump to latest.

Browser run `18361` again showed one tab after the shortcut removed the terminal pane. This indicates the pagination page was restoring an older tab from origin storage; its first empty-DOM checks can run before the lazy workspace import finishes. I now unmount the main page from Terminals before clearing the shared workspace key, assert the active pane-owned tab ID disappears after `Ctrl+Shift+W`, then restore the main page URL. `node --check` and `git diff --check` pass. The prior run still measured container detail 111,965 B, AI agent tokens 107,695 B, Terminals 108,509 B, and passed `Jump to latest`.
Author
Owner

Browser run 18362 measured the expected cold route budgets and passed Jump to latest; the pagination session became detached when its pane disappeared, but the owning tab ID still remained after the shortcut. To isolate the pagination coverage from workspace-tab close behavior, the loop now detaches each real terminal by navigating away from Terminals, clears its persisted workspace key after unmount, checks the server session is detached, then returns to an empty Terminals page before creating the next session. node --check and git diff --check pass.

Browser run `18362` measured the expected cold route budgets and passed `Jump to latest`; the pagination session became detached when its pane disappeared, but the owning tab ID still remained after the shortcut. To isolate the pagination coverage from workspace-tab close behavior, the loop now detaches each real terminal by navigating away from Terminals, clears its persisted workspace key after unmount, checks the server session is `detached`, then returns to an empty Terminals page before creating the next session. `node --check` and `git diff --check` pass.
Author
Owner

Browser run 18363 passed route budgets, the session fixtures, and the “Jump to latest” check. It then failed while the pagination loop opened many persistent sessions. Inspection found the harness paired OPEN requests and OPEN_OK frames by numeric channel alone, even across route navigation that creates new WebSocket connections; channel IDs can be reused, so this can select a stale OPEN_OK. I am correcting the harness to pair by WebSocket connection and channel before deciding whether the missing pane session ID is a product defect.

Browser run 18363 passed route budgets, the session fixtures, and the “Jump to latest” check. It then failed while the pagination loop opened many persistent sessions. Inspection found the harness paired OPEN requests and OPEN_OK frames by numeric channel alone, even across route navigation that creates new WebSocket connections; channel IDs can be reused, so this can select a stale OPEN_OK. I am correcting the harness to pair by WebSocket connection and channel before deciding whether the missing pane session ID is a product defect.
Author
Owner

Browser run 18364 no longer had the channel-only correlation ambiguity, but still failed in checkSessionPagination: openTerminalWorkspaceTab timed out after 10 seconds waiting for the new pane's data-session-id (empty string). The release binary and browser suite started successfully; later browser checks did not run. I added a sanitized failure snapshot for the exact stream connection/channel, OPEN_OK metadata presence, and mounted pane status/error so the next run can identify whether OPEN_OK was rejected or the callback/state update was missed.

Browser run 18364 no longer had the channel-only correlation ambiguity, but still failed in `checkSessionPagination`: `openTerminalWorkspaceTab` timed out after 10 seconds waiting for the new pane's `data-session-id` (empty string). The release binary and browser suite started successfully; later browser checks did not run. I added a sanitized failure snapshot for the exact stream connection/channel, OPEN_OK metadata presence, and mounted pane status/error so the next run can identify whether OPEN_OK was rejected or the callback/state update was missed.
Author
Owner

The 18365 diagnostic confirmed the failure occurs after a new exec OPEN is sent and a pane mounts, but the prior recorder reported no qualifying OPEN_OK. That recorder only retained OPEN_OK frames with both session_id and output_offset, so the result could have been filtered metadata or an OPEN_ERR. Its status query was also using classes absent from the pane markup. I changed it to record all OPEN_OK metadata types and safe OPEN_ERR code/retryability, and read the pane's actual role=status/alert text. The gate also passed “Jump to latest” before failing the session-ID wait.

The 18365 diagnostic confirmed the failure occurs after a new exec OPEN is sent and a pane mounts, but the prior recorder reported no qualifying OPEN_OK. That recorder only retained OPEN_OK frames with both session_id and output_offset, so the result could have been filtered metadata or an OPEN_ERR. Its status query was also using classes absent from the pane markup. I changed it to record all OPEN_OK metadata types and safe OPEN_ERR code/retryability, and read the pane's actual role=status/alert text. The gate also passed “Jump to latest” before failing the session-ID wait.
Author
Owner

Browser run 18366 captured the exact failure: the exec OPEN returned retryable resource_exhausted, and the pane showed “The session limit has been reached.” The harness was detaching each terminal between iterations but leaving its shell running; the real persistent exec manager allows 16 live sessions per user, so the 17th OPEN correctly failed. Its total retained-session cap is 64, which still permits the test’s 51-record pagination inventory if each shell is exited after OPEN_OK. I’ll update the harness to run exit, verify the session is listed as exited, then continue with the remaining real detached-session and pagination checks; production limits stay intact.

Browser run 18366 captured the exact failure: the exec OPEN returned retryable `resource_exhausted`, and the pane showed “The session limit has been reached.” The harness was detaching each terminal between iterations but leaving its shell running; the real persistent exec manager allows 16 live sessions per user, so the 17th OPEN correctly failed. Its total retained-session cap is 64, which still permits the test’s 51-record pagination inventory if each shell is exited after OPEN_OK. I’ll update the harness to run `exit`, verify the session is listed as exited, then continue with the remaining real detached-session and pagination checks; production limits stay intact.
Author
Owner

Run 18367 got past the live-session quota: the newly opened terminal reached a shell prompt, exit completed it, and the real session list returned state exited. The next loop iteration failed because page.goto('/terminals', waitUntil: 'networkidle') timed out at 30 seconds after navigation from Containers. I’ll use domcontentloaded for these repeated SPA route transitions and keep explicit assertions for the owned route title, no mounted terminal panes, and no close controls before continuing.

Run 18367 got past the live-session quota: the newly opened terminal reached a shell prompt, `exit` completed it, and the real session list returned state `exited`. The next loop iteration failed because `page.goto('/terminals', waitUntil: 'networkidle')` timed out at 30 seconds after navigation from Containers. I’ll use `domcontentloaded` for these repeated SPA route transitions and keep explicit assertions for the owned route title, no mounted terminal panes, and no close controls before continuing.
Author
Owner

Run 18368 cleared the first session-quota issue and “Jump to latest”; it advanced to the shell cleanup step. After sending exit, the pane status remained “Attached. Replaying available output.” for 10 seconds, so the quota could not be released. I’m changing the cleanup command to print a unique marker immediately before exiting, asserting the marker arrived, and recording the server’s session state if the close still does not arrive.

Run 18368 cleared the first session-quota issue and “Jump to latest”; it advanced to the shell cleanup step. After sending `exit`, the pane status remained “Attached. Replaying available output.” for 10 seconds, so the quota could not be released. I’m changing the cleanup command to print a unique marker immediately before exiting, asserting the marker arrived, and recording the server’s session state if the close still does not arrive.
Author
Owner

Run 18369 passed the route budgets and “Jump to latest,” then successfully delivered printf …; exit to the real shell. The terminal transcript wrapped the long unique marker across rows at the current pane width, so Playwright’s exact substring assertion failed before the exit-state check. I’ll shorten the marker below one row and rerun; this is a harness assertion issue, not an OPEN failure.

Run 18369 passed the route budgets and “Jump to latest,” then successfully delivered `printf …; exit` to the real shell. The terminal transcript wrapped the long unique marker across rows at the current pane width, so Playwright’s exact substring assertion failed before the exit-state check. I’ll shorten the marker below one row and rerun; this is a harness assertion issue, not an OPEN failure.
Author
Owner

Run 18370 passed route budgets and “Jump to latest,” completed the first pagination shell, then failed to deliver the short marker into the second shell: its transcript stayed at the prompt, with no echoed command. The pagination flow had inherited the 390px viewport from the preceding mobile matrix and did not assert keyboard focus before typing. I’ll reset that interaction to 1440×900, assert the terminal is focused, and capture a sanitized focus/transcript/session-state snapshot if input still does not arrive.

Run 18370 passed route budgets and “Jump to latest,” completed the first pagination shell, then failed to deliver the short marker into the second shell: its transcript stayed at the prompt, with no echoed command. The pagination flow had inherited the 390px viewport from the preceding mobile matrix and did not assert keyboard focus before typing. I’ll reset that interaction to 1440×900, assert the terminal is focused, and capture a sanitized focus/transcript/session-state snapshot if input still does not arrive.
Author
Owner

Run 18371 confirmed the shell input target was focused at 1440px/128 columns, yet the pane showed “You do not have access to this terminal target” and the real session summary was detached; the marker never arrived. This rules out the mobile viewport and simple focus loss. I’m tracing the real container fixture lifecycle and matching stream OPEN/CLOSE error metadata before changing product code.

Run 18371 confirmed the shell input target was focused at 1440px/128 columns, yet the pane showed “You do not have access to this terminal target” and the real session summary was `detached`; the marker never arrived. This rules out the mobile viewport and simple focus loss. I’m tracing the real container fixture lifecycle and matching stream OPEN/CLOSE error metadata before changing product code.
Author
Owner

Browser run 18372 passed the “Jump to latest” check and measured the AI agent tokens route at 107,695 gzip bytes. It then timed out after 30 seconds waiting for networkidle on the initial /terminals navigation in checkSessionPagination, before any pagination terminal was opened. No new stream authorization evidence was produced. I’m changing that fixture navigation to DOM readiness plus explicit route/workspace assertions, then will rerun the browser gate.

Browser run 18372 passed the “Jump to latest” check and measured the AI agent tokens route at 107,695 gzip bytes. It then timed out after 30 seconds waiting for `networkidle` on the initial `/terminals` navigation in `checkSessionPagination`, before any pagination terminal was opened. No new stream authorization evidence was produced. I’m changing that fixture navigation to DOM readiness plus explicit route/workspace assertions, then will rerun the browser gate.
Author
Owner

Browser run 18373 captured the exact stream outcome: a persistent exec OPEN_OK returned session_id/replay metadata, then the same WebSocket/channel received CLOSE {error: forbidden, retryable: false}; the session became detached and only 4 output bytes arrived. There was no OPEN_ERR, and the focused 1440px terminal input remained at the prompt. The auth trace shows main page 1 and terminal page 11 repeatedly receiving stale-token 401s followed by successful refreshes. refresh_session revokes the previous access-token row and increments its auth epoch, which explains the forced CLOSE. I’m adding regression coverage for requesting the current session from an active tab before a stale tab rotates the shared refresh cookie.

Browser run 18373 captured the exact stream outcome: a persistent exec OPEN_OK returned `session_id`/replay metadata, then the same WebSocket/channel received `CLOSE {error: forbidden, retryable: false}`; the session became detached and only 4 output bytes arrived. There was no OPEN_ERR, and the focused 1440px terminal input remained at the prompt. The auth trace shows main page 1 and terminal page 11 repeatedly receiving stale-token 401s followed by successful refreshes. `refresh_session` revokes the previous access-token row and increments its auth epoch, which explains the forced CLOSE. I’m adding regression coverage for requesting the current session from an active tab before a stale tab rotates the shared refresh cookie.
Author
Owner

The 18373 CLOSE forbidden trace was caused by cross-tab refresh rotation. The browser app revokes the previous access token on every successful cookie refresh; an authenticated second page missed the BroadcastChannel announcement, then rotated again and revoked the terminal page's stream token.

I added request/reply over the existing BroadcastChannel: a tab whose in-memory generation lags the shared nonsecret generation asks live peers for the current session and waits 250 ms before falling back to cookie refresh. Peers reply only when their session generation is at least the requested generation. Access tokens remain memory-only, recipients still adopt only during a pending refresh, and sign-out fencing is unchanged.

TDD evidence: the three new peer-response/adoption/fallback tests failed before the implementation; targeted auth.test.ts now passes 17/17. scripts/verify fast passed all 16 steps:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
The 18373 `CLOSE forbidden` trace was caused by cross-tab refresh rotation. The browser app revokes the previous access token on every successful cookie refresh; an authenticated second page missed the BroadcastChannel announcement, then rotated again and revoked the terminal page's stream token. I added request/reply over the existing BroadcastChannel: a tab whose in-memory generation lags the shared nonsecret generation asks live peers for the current session and waits 250 ms before falling back to cookie refresh. Peers reply only when their session generation is at least the requested generation. Access tokens remain memory-only, recipients still adopt only during a pending refresh, and sign-out fencing is unchanged. TDD evidence: the three new peer-response/adoption/fallback tests failed before the implementation; targeted `auth.test.ts` now passes 17/17. `scripts/verify fast` passed all 16 steps: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Browser run 18374 exercised the new session handoff and failed an outdated multi-tab fixture assertion: with the original authenticated page still active, both new pages adopted its in-memory token, so the refresh request count was 0 instead of the fixture's expected 1. That is the intended session-sharing behavior. I’ve isolated the existing lock-race test by navigating its original page to about:blank first; it will continue to verify one refresh among two simultaneous fresh tabs. The real two-page terminal pagination case remains active for checking that sharing prevents stream-token revocation.

Browser run 18374 exercised the new session handoff and failed an outdated multi-tab fixture assertion: with the original authenticated page still active, both new pages adopted its in-memory token, so the refresh request count was 0 instead of the fixture's expected 1. That is the intended session-sharing behavior. I’ve isolated the existing lock-race test by navigating its original page to `about:blank` first; it will continue to verify one refresh among two simultaneous fresh tabs. The real two-page terminal pagination case remains active for checking that sharing prevents stream-token revocation.
Author
Owner

Browser run 18375 stalled in the existing pending-refresh/sign-out check. That test waits for an intercepted /auth/refresh request, but the active original tab now answers the new page’s session request, so no refresh request is sent. I stopped only the owned browser-check Bun process after confirming it was the sole verify gate; the outer verifier exited and ps, Docker and Podman checks confirmed no owned process or fixture remained. I’ll make the pending page start with no stored session generation, preserving BroadcastChannel delivery for sign-out, and bound the wait for its intercepted refresh.

Browser run 18375 stalled in the existing pending-refresh/sign-out check. That test waits for an intercepted `/auth/refresh` request, but the active original tab now answers the new page’s session request, so no refresh request is sent. I stopped only the owned browser-check Bun process after confirming it was the sole verify gate; the outer verifier exited and `ps`, Docker and Podman checks confirmed no owned process or fixture remained. I’ll make the pending page start with no stored session generation, preserving BroadcastChannel delivery for sign-out, and bound the wait for its intercepted refresh.
Author
Owner

Browser run 18376 on calternal-port at 5772ebd reached the release server and failed before the route matrix at the stream socket assertion. Safe evidence: container-detail cold JS gzip was 112,009 bytes; AI agent tokens route gzip was 107,735 bytes; Terminals route gzip was 108,549 bytes. The assertion observed 4 live stream WebSockets before opening the direct terminal and 5 afterward. I added sanitized per-socket route and OPEN-kind diagnostics to scripts/browser-check.mjs; next I’m rerunning the browser gate to determine whether these are retained workspace/log attachments or duplicate connections. No token or session identifiers are included.

Browser run 18376 on `calternal-port` at `5772ebd` reached the release server and failed before the route matrix at the stream socket assertion. Safe evidence: container-detail cold JS gzip was 112,009 bytes; AI agent tokens route gzip was 107,735 bytes; Terminals route gzip was 108,549 bytes. The assertion observed 4 live stream WebSockets before opening the direct terminal and 5 afterward. I added sanitized per-socket route and OPEN-kind diagnostics to `scripts/browser-check.mjs`; next I’m rerunning the browser gate to determine whether these are retained workspace/log attachments or duplicate connections. No token or session identifiers are included.
Author
Owner

Browser run 18377 on calternal-port at 82798d0 reproduced the stream-count failure with useful sanitized evidence: four earlier live WebSockets each carried one logs OPEN from Container detail; opening the direct terminal added one exec OPEN. The failure still precedes the route matrix. I added a document-generation label to distinguish stale references from simultaneous active-page sockets; the count assertion is unchanged pending that evidence.

Correction to my prior run setup: scripts/verify reads INFRATERNAL_ARTIFACT_DIR (without “mi”) and defaults to /mnt/hdd/infraternal/artifacts/fix-terminal. Run 18377 used the misspelled name; the eight terminal captures there are byte-identical to run 18376. The next run will use the correct override under /mnt/hdd/infraternal/artifacts/port-final/run-18378.

Browser run 18377 on `calternal-port` at `82798d0` reproduced the stream-count failure with useful sanitized evidence: four earlier live WebSockets each carried one `logs` OPEN from Container detail; opening the direct terminal added one `exec` OPEN. The failure still precedes the route matrix. I added a document-generation label to distinguish stale references from simultaneous active-page sockets; the count assertion is unchanged pending that evidence. Correction to my prior run setup: `scripts/verify` reads `INFRATERNAL_ARTIFACT_DIR` (without “mi”) and defaults to `/mnt/hdd/infraternal/artifacts/fix-terminal`. Run 18377 used the misspelled name; the eight terminal captures there are byte-identical to run 18376. The next run will use the correct override under `/mnt/hdd/infraternal/artifacts/port-final/run-18378`.
Author
Owner

Correction to my previous artifact note: scripts/verify's /mnt/hdd/infraternal/artifacts/fix-terminal fallback is only used by terminal-specific checks. Since browser-check.mjs received no correctly spelled INFRATERNAL_ARTIFACT_DIR, run 18377 used the browser script's own /mnt/hdd/infraternal/artifacts/port-ab fallback and wrote eight terminal captures there. Their hashes differ from run 18376; I am leaving that directory untouched. The next browser run uses the correctly spelled override to write only under /mnt/hdd/infraternal/artifacts/port-final/run-18378.

Correction to my previous artifact note: `scripts/verify`'s `/mnt/hdd/infraternal/artifacts/fix-terminal` fallback is only used by terminal-specific checks. Since `browser-check.mjs` received no correctly spelled `INFRATERNAL_ARTIFACT_DIR`, run 18377 used the browser script's own `/mnt/hdd/infraternal/artifacts/port-ab` fallback and wrote eight terminal captures there. Their hashes differ from run 18376; I am leaving that directory untouched. The next browser run uses the correctly spelled override to write only under `/mnt/hdd/infraternal/artifacts/port-final/run-18378`.
Author
Owner

Browser run 18378 on calternal-port at a494404 narrowed the 4→5 count: the four log WebSocket records belong to document generations 26, 29, 31 and 33; the direct exec socket belongs to current generation 35. The gate still stops before route captures. Playwright's per-socket close callbacks did not mark the old records closed, so I added Chromium Network WebSocket lifecycle instrumentation to confirm transport closure before changing the assertion or app behavior. Chromium documents Network.webSocketClosed as its WebSocket-closure event: Chrome DevTools Protocol Network.

Browser run 18378 on `calternal-port` at `a494404` narrowed the 4→5 count: the four log WebSocket records belong to document generations 26, 29, 31 and 33; the direct exec socket belongs to current generation 35. The gate still stops before route captures. Playwright's per-socket `close` callbacks did not mark the old records closed, so I added Chromium Network WebSocket lifecycle instrumentation to confirm transport closure before changing the assertion or app behavior. Chromium documents `Network.webSocketClosed` as its WebSocket-closure event: [Chrome DevTools Protocol Network](https://chromedevtools.github.io/devtools-protocol/tot/Network/#event-webSocketClosed).
Author
Owner

Browser run 18379 reached the real inventory check but the unique Podman fixture was absent from the unfiltered API response (total: 0, target absent); the gate removed its fixture during teardown. Run 18380 confirmed the fixture present (total: 173, target present; filtered inventory total: 1) and reached the terminal check. Chromium CDP showed four log WebSockets still network-active from Container-detail document generations 26, 29, 31 and 33 after opening the direct exec socket in generation 35. The terminal check fails with 4 active streams before and 5 after. This confirms a transport lifecycle defect, not just stale Playwright socket bookkeeping. Correct run artifacts are in /mnt/hdd/infraternal/artifacts/port-final/run-18380 (56 screenshots; matrix capture did not run because the stream assertion failed).

Browser run 18379 reached the real inventory check but the unique Podman fixture was absent from the unfiltered API response (`total: 0`, target absent); the gate removed its fixture during teardown. Run 18380 confirmed the fixture present (`total: 173`, target present; filtered inventory `total: 1`) and reached the terminal check. Chromium CDP showed four log WebSockets still network-active from Container-detail document generations 26, 29, 31 and 33 after opening the direct exec socket in generation 35. The terminal check fails with 4 active streams before and 5 after. This confirms a transport lifecycle defect, not just stale Playwright socket bookkeeping. Correct run artifacts are in `/mnt/hdd/infraternal/artifacts/port-final/run-18380` (56 screenshots; matrix capture did not run because the stream assertion failed).
Author
Owner

Orchestrator, 19:10 IST: approved the stream-lifecycle design. Views own their attachments; the transport closes after about 5 s idle at zero refcount; pagehide closes every transport and pageshow reattaches the mounted views; the server pings with a pong deadline. Also logs open with tail 1000, and polling is single-flight and visible-only. port-final has resumed.

Orchestrator, 19:10 IST: approved the stream-lifecycle design. Views own their attachments; the transport closes after about 5 s idle at zero refcount; pagehide closes every transport and pageshow reattaches the mounted views; the server pings with a pong deadline. Also logs open with tail 1000, and polling is single-flight and visible-only. port-final has resumed.
Author
Owner

Continuation resumed on calternal-port at b3b125e7fb19f6d66ba82f1244c1c1120df77783; the worktree’s recorded base is 4870b301b789840f6ae5d69d13756b9197f25d10. I’m proceeding with the approved transport lifecycle, issue #46 integration scope, Lane D removal, remaining UI defects, and required gates/plates. The latest browser evidence is that four log sockets from old document generations remained network-active after route navigation; the current diagnostic changes are committed through b3b125e.

Continuation resumed on `calternal-port` at `b3b125e7fb19f6d66ba82f1244c1c1120df77783`; the worktree’s recorded base is `4870b301b789840f6ae5d69d13756b9197f25d10`. I’m proceeding with the approved transport lifecycle, issue #46 integration scope, Lane D removal, remaining UI defects, and required gates/plates. The latest browser evidence is that four log sockets from old document generations remained network-active after route navigation; the current diagnostic changes are committed through `b3b125e`.
Author
Owner

Orchestrator: frontend audit findings to apply after port-final lands (job /mnt/hdd/infraternal/jobs/audit-frontend/report.md):

  • F2: sidebar persistence bypasses the shared 401 refresh path.
  • F3: sidebar save retries mint a new idempotency key each time.
  • F4/F6: keyed single-flight polling, as a small lib/data layer.
  • F5: the terminal transcript snapshots the full screen on every write.
  • F7: host sort recomputes on every poll.
  • F8/F9: move shared product components out of the route folders, and delete the orphan ImageReference.
  • F10: the __ui-tests route ships in the product.
    The audit found no shadcn, bits-ui, tailwind-variants, tw-animate or cn left at b3b125e.
Orchestrator: frontend audit findings to apply after port-final lands (job `/mnt/hdd/infraternal/jobs/audit-frontend/report.md`): - **F2:** sidebar persistence bypasses the shared 401 refresh path. - **F3:** sidebar save retries mint a new idempotency key each time. - **F4/F6:** keyed single-flight polling, as a small `lib/data` layer. - **F5:** the terminal transcript snapshots the full screen on every write. - **F7:** host sort recomputes on every poll. - **F8/F9:** move shared product components out of the route folders, and delete the orphan `ImageReference`. - **F10:** the `__ui-tests` route ships in the product. The audit found no shadcn, bits-ui, tailwind-variants, tw-animate or cn left at `b3b125e`.
Author
Owner

Continuation implementation on calternal-port:

  • Added 5-second zero-attachment socket retirement, immediate pagehide teardown, persisted pageshow reattach, and reset of the non-resumable log tail before reopening.
  • Dashboard, Containers and Hosts now share visible-only single-flight polling with stale-response generations. Focused tests: 9 passed; Svelte check: 0 errors, 0 warnings.
  • Log OPEN now requests {tail: 1000, follow: true}. The view reports retained lines/bytes and distinguishes rolled-off history from rejected records.
  • Added a server WebSocket control Ping every 15 seconds and a matching-Pong deadline of 10 seconds; timeout exits the existing connection loop with 4008. Added a raw WebSocket regression that does not send Pong.
  • Commits: 193609f, 3240f7e, 9bff41b.
  • Browser check now covers synthetic persisted pagehide/pageshow reattachment, 50 SPA transitions, 20 reloads, log channel CLOSE and post-close DATA, zero active sockets, and exactly one socket for one terminal. Its gate remains pending; the shared VM currently has a scripts/verify merge process, so I am waiting before starting integration/browser.
Continuation implementation on `calternal-port`: - Added 5-second zero-attachment socket retirement, immediate `pagehide` teardown, persisted `pageshow` reattach, and reset of the non-resumable log tail before reopening. - Dashboard, Containers and Hosts now share visible-only single-flight polling with stale-response generations. Focused tests: 9 passed; Svelte check: 0 errors, 0 warnings. - Log OPEN now requests `{tail: 1000, follow: true}`. The view reports retained lines/bytes and distinguishes rolled-off history from rejected records. - Added a server WebSocket control Ping every 15 seconds and a matching-Pong deadline of 10 seconds; timeout exits the existing connection loop with 4008. Added a raw WebSocket regression that does not send Pong. - Commits: `193609f`, `3240f7e`, `9bff41b`. - Browser check now covers synthetic persisted pagehide/pageshow reattachment, 50 SPA transitions, 20 reloads, log channel CLOSE and post-close DATA, zero active sockets, and exactly one socket for one terminal. Its gate remains pending; the shared VM currently has a `scripts/verify merge` process, so I am waiting before starting integration/browser.
Author
Owner

Fast gate result for calternal-port at 1dc42f4:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Fast gate result for `calternal-port` at `1dc42f4`: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Orchestrator: dev is now 4952934 with tiered gates; scripts/verify merge is the merge gate. port-final: merge origin/dev and use fast plus merge for your final gates.

Orchestrator: `dev` is now `4952934` with tiered gates; `scripts/verify merge` is the merge gate. port-final: merge `origin/dev` and use `fast` plus `merge` for your final gates.
Author
Owner

Integration gate result for calternal-port at 1dc42f4 (CARGO_BUILD_JOBS=2):

PASS integration: JavaScript dependencies
PASS integration: build web app
PASS integration: build release binary
PASS integration: real HTTP behavior
PASS integration: Docker socket _ping
PASS integration: rootless Podman socket _ping
PASS integration: engine adapters against Docker and Podman
PASS integration: bounded follow:false log snapshots against Docker and rootless Podman
PASS integration: TypeScript stream client against Docker and Podman
PASS integration: stream authorization and CLOSE regressions against Docker
PASS integration: persistent PTY termination preempts blocked send
PASS integration: resource HTTP API against Docker and rootless Podman
PASS integration: compiled CLI and MCP against real server and engines
PASS integration: SSH contract against isolated real sshd
PASS integration: SSH product API and stream against isolated real sshd
PASS integration: remote mTLS infraternal agent enroll, rotate, list, exec and revoke against Docker
Integration gate result for `calternal-port` at `1dc42f4` (`CARGO_BUILD_JOBS=2`): ```text PASS integration: JavaScript dependencies PASS integration: build web app PASS integration: build release binary PASS integration: real HTTP behavior PASS integration: Docker socket _ping PASS integration: rootless Podman socket _ping PASS integration: engine adapters against Docker and Podman PASS integration: bounded follow:false log snapshots against Docker and rootless Podman PASS integration: TypeScript stream client against Docker and Podman PASS integration: stream authorization and CLOSE regressions against Docker PASS integration: persistent PTY termination preempts blocked send PASS integration: resource HTTP API against Docker and rootless Podman PASS integration: compiled CLI and MCP against real server and engines PASS integration: SSH contract against isolated real sshd PASS integration: SSH product API and stream against isolated real sshd PASS integration: remote mTLS infraternal agent enroll, rotate, list, exec and revoke against Docker ```
Author
Owner

Browser finding on calternal-port at 1dc42f4: the first browser run reached the unsupported multi-tab auth checks, then timed out after 30 seconds at checkSharedCookieTabs line 2082. The two tabs were continuing their container refresh and one-use-cookie recovery requests while the harness waited for networkidle; the Containers heading and later search/recovery assertions provide the behavior checks. I am changing only those two navigations to wait for domcontentloaded, retaining the heading and recovered-request assertions.

Browser finding on `calternal-port` at `1dc42f4`: the first browser run reached the unsupported multi-tab auth checks, then timed out after 30 seconds at `checkSharedCookieTabs` line 2082. The two tabs were continuing their container refresh and one-use-cookie recovery requests while the harness waited for `networkidle`; the Containers heading and later search/recovery assertions provide the behavior checks. I am changing only those two navigations to wait for `domcontentloaded`, retaining the heading and recovered-request assertions.
Author
Owner

Browser harness fix committed as e854b61: the unsupported multi-tab auth checks now wait for DOM content rather than network idle when navigating to Containers. The suite still asserts the Containers heading and recovered search response, so the active polling/re-auth traffic no longer blocks navigation readiness.

Browser harness fix committed as `e854b61`: the unsupported multi-tab auth checks now wait for DOM content rather than network idle when navigating to Containers. The suite still asserts the Containers heading and recovered search response, so the active polling/re-auth traffic no longer blocks navigation readiness.
Author
Owner

Browser run 2 on 1dc42f4 / harness fix e854b61:

  • PASS browser log control: Jump to latest occurred twice.
  • METRIC container-detail JS gzip before terminal: 112030 bytes
  • METRIC ai-agent-tokens route JS gzip: 107755 bytes
  • METRIC terminals route JS gzip: 108570 bytes
  • Failure: after navigating from container logs to Hosts, the prior log socket did not report close within 5 seconds. This happened before page.goBack() and before the persisted lifecycle assertion, so this run does not establish whether BFCache restored the page.

The browser harness now records the open-to-socket mapping, pagehide events, live network sockets, and Chromium not-restored reasons to identify whether the app close callback or the test correlation is wrong.

Browser run 2 on `1dc42f4` / harness fix `e854b61`: - `PASS browser log control: Jump to latest` occurred twice. - `METRIC container-detail JS gzip before terminal: 112030 bytes` - `METRIC ai-agent-tokens route JS gzip: 107755 bytes` - `METRIC terminals route JS gzip: 108570 bytes` - Failure: after navigating from container logs to Hosts, the prior log socket did not report `close` within 5 seconds. This happened before `page.goBack()` and before the persisted lifecycle assertion, so this run does not establish whether BFCache restored the page. The browser harness now records the open-to-socket mapping, pagehide events, live network sockets, and Chromium not-restored reasons to identify whether the app close callback or the test correlation is wrong.
Author
Owner

Browser run 3 confirms a stream lifecycle defect after the socket ID counter was scoped to /api/v1/stream: the current log OPEN maps to tracked socket 5 (logOpens: 1), but after 5 seconds the current page reports pagehide.persisted=false and five network stream sockets remain active (document generations 26, 29, 31, 33, and 37). The browser had reached the pagehide test and did not reach the back navigation. I added a diagnostic wrapper to record whether WebSocket.close() is actually invoked during pagehide and its ready state.

Browser run 3 confirms a stream lifecycle defect after the socket ID counter was scoped to `/api/v1/stream`: the current log OPEN maps to tracked socket 5 (`logOpens: 1`), but after 5 seconds the current page reports `pagehide.persisted=false` and five network stream sockets remain active (document generations 26, 29, 31, 33, and 37). The browser had reached the pagehide test and did not reach the back navigation. I added a diagnostic wrapper to record whether `WebSocket.close()` is actually invoked during pagehide and its ready state.
Author
Owner

Stream lifecycle finding and fix on calternal-port: run 4 recorded WebSocket.close(1000, "client closed") at readyState OPEN on pagehide, yet five old stream sockets remained network-active. In run_connection, a client Close previously entered channel/engine teardown before the split WebSocket transport was dropped. The close path now drops both transport halves and awaits the writer before channel teardown, preserving the contract that the server does not mirror client close codes. Added an integration regression and updated §3.10.

Targeted test output:

   Compiling infraternal-server v0.0.1 (/home/kayg/wt/calternal-port/crates/server)
    Finished `test` profile [unoptimized] target(s) in 20.41s
     Running tests/stream_regressions.rs (target/debug/deps/stream_regressions-48e002253e6b1803)

running 1 test
test websocket_client_close_drops_the_transport_before_engine_cleanup ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 20 filtered out; finished in 0.07s

Stream lifecycle finding and fix on `calternal-port`: run 4 recorded `WebSocket.close(1000, "client closed")` at readyState OPEN on pagehide, yet five old stream sockets remained network-active. In `run_connection`, a client Close previously entered channel/engine teardown before the split WebSocket transport was dropped. The close path now drops both transport halves and awaits the writer before channel teardown, preserving the contract that the server does not mirror client close codes. Added an integration regression and updated §3.10. Targeted test output: ```text Compiling infraternal-server v0.0.1 (/home/kayg/wt/calternal-port/crates/server) Finished `test` profile [unoptimized] target(s) in 20.41s Running tests/stream_regressions.rs (target/debug/deps/stream_regressions-48e002253e6b1803) running 1 test test websocket_client_close_drops_the_transport_before_engine_cleanup ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 20 filtered out; finished in 0.07s ```
Author
Owner

Final fast gate on calternal-port at 96ef6f0:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Final fast gate on `calternal-port` at `96ef6f0`: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Integration gate on 96ef6f0 reached and passed JavaScript dependencies, web build, release binary, real HTTP behavior, Docker and rootless Podman socket checks, engine adapters, bounded log snapshots, TypeScript stream client, stream authorization/CLOSE regressions, PTY termination, and resource HTTP API checks.

It then failed at compiled CLI and MCP against real server and engines. The ignored cli_and_mcp_use_the_public_http_contract test timed out in its PTY harness. The failing case was the SIGKILL/re-attach SSH replay path: captured output included the post-detach replay marker and the finish input, but the compiled CLI did not exit within the 15-second harness deadline. I am tracing the terminal close path and will rerun the focused real-sshd scenario after diagnosis.

Integration gate on `96ef6f0` reached and passed JavaScript dependencies, web build, release binary, real HTTP behavior, Docker and rootless Podman socket checks, engine adapters, bounded log snapshots, TypeScript stream client, stream authorization/CLOSE regressions, PTY termination, and resource HTTP API checks. It then failed at `compiled CLI and MCP against real server and engines`. The ignored `cli_and_mcp_use_the_public_http_contract` test timed out in its PTY harness. The failing case was the SIGKILL/re-attach SSH replay path: captured output included the post-detach replay marker and the `finish` input, but the compiled CLI did not exit within the 15-second harness deadline. I am tracing the terminal close path and will rerun the focused real-sshd scenario after diagnosis.
Author
Owner

A focused run of the compiled cli_mcp real-sshd test, with container/API phases bypassed, failed earlier than the SIGKILL replay path: run_cli_with_input_timeout did not observe the CLI exit within five seconds after piped stdin EOF. The CLI had opened the SSH session, but stderr contained no remote-exit error. This suggests close delivery or the test deadline needs further isolation; I have not classified it as a product regression yet.

A focused run of the compiled `cli_mcp` real-sshd test, with container/API phases bypassed, failed earlier than the SIGKILL replay path: `run_cli_with_input_timeout` did not observe the CLI exit within five seconds after piped stdin EOF. The CLI had opened the SSH session, but stderr contained no remote-exit error. This suggests close delivery or the test deadline needs further isolation; I have not classified it as a product regression yet.
Author
Owner

The focused real-sshd rerun passed after the shared verify queue cleared: cli_and_mcp_use_the_public_http_contract completed with INFRATER...SSH_ONLY enabled in 13.24 seconds (1 passed). Its earlier five-second piped-stdin timeout occurred while a release merge and another fast gate were active, so contention is a plausible cause, but the full integration rerun is still required to confirm.

The focused real-sshd rerun passed after the shared verify queue cleared: `cli_and_mcp_use_the_public_http_contract` completed with `INFRATER...SSH_ONLY` enabled in 13.24 seconds (`1 passed`). Its earlier five-second piped-stdin timeout occurred while a release merge and another fast gate were active, so contention is a plausible cause, but the full integration rerun is still required to confirm.
Author
Owner

Correction to my previous #46 update: the focused real-sshd run used INFRATER...? No: its exact selector was INFRATERNAL_CLI_MCP_SSH_ONLY=1; I abbreviated it incorrectly in the prior comment. The 13.24-second passing result is unchanged.

Correction to my previous #46 update: the focused real-sshd run used `INFRATER...`? No: its exact selector was `INFRATERNAL_CLI_MCP_SSH_ONLY=1`; I abbreviated it incorrectly in the prior comment. The 13.24-second passing result is unchanged.
Author
Owner

For clarity, the exact selector was INFRATERNAL_CLI_MCP_SSH_ONLY=1. Ignore the placeholder phrase included in my immediately previous correction; the test result remains 1 passed in 13.24 seconds.

For clarity, the exact selector was `INFRATERNAL_CLI_MCP_SSH_ONLY=1`. Ignore the placeholder phrase included in my immediately previous correction; the test result remains `1 passed` in 13.24 seconds.
Author
Owner

Orchestrator: dev is now 6f6fd89 and is deployed on o2. It adds the security hardening (#48: owner-safe pre-login quotas, private storage, a cross-process refresh lock, redacted rejection audit, enrollment idempotency, AI identity revoke denial; migrations 0017–0020) and a deploy-container fix for the js install lock. Your next migration number must be above 0020. Merge origin/dev before your final gates.

Orchestrator: `dev` is now `6f6fd89` and is deployed on o2. It adds the security hardening (#48: owner-safe pre-login quotas, private storage, a cross-process refresh lock, redacted rejection audit, enrollment idempotency, AI identity revoke denial; migrations 0017–0020) and a deploy-container fix for the js install lock. **Your next migration number must be above 0020.** Merge `origin/dev` before your final gates.
Author
Owner

Continuation resumed on branch calternal-port at 96ef6f0. Fetched origin/dev at 6f6fd896; it advanced since the prior merge and will be merged after the currently active shared integration gate exits. At 18:46 local, another worktree's scripts/verify integration was active; load5 was 3.60. I will rerun this branch's integration and browser gates serially, then complete the route plates and final visual review.

Continuation resumed on branch `calternal-port` at `96ef6f0`. Fetched `origin/dev` at `6f6fd896`; it advanced since the prior merge and will be merged after the currently active shared integration gate exits. At 18:46 local, another worktree's `scripts/verify integration` was active; load5 was 3.60. I will rerun this branch's integration and browser gates serially, then complete the route plates and final visual review.
Author
Owner

Merged fetched origin/dev 6f6fd896 into calternal-port as 456cee5. The browser-harness conflict retained the full route/screenshots and stream lifecycle acceptance (50 SPA transitions and 20 reloads), and adopted the latest validated INFRATERNAL_RUN_ID with infraternal.test.run labels for scoped fixture cleanup. The upstream .ui-table-header selector does not exist in the port's current table; the retained browser check targets the rendered .resource-header. node --check scripts/browser-check.mjs, bash -n scripts/verify, and git diff --cached --check passed before commit. A shared integration gate was active after the merge, so the post-merge fast gate is queued behind it.

Merged fetched `origin/dev` `6f6fd896` into `calternal-port` as `456cee5`. The browser-harness conflict retained the full route/screenshots and stream lifecycle acceptance (50 SPA transitions and 20 reloads), and adopted the latest validated `INFRATERNAL_RUN_ID` with `infraternal.test.run` labels for scoped fixture cleanup. The upstream `.ui-table-header` selector does not exist in the port's current table; the retained browser check targets the rendered `.resource-header`. `node --check scripts/browser-check.mjs`, `bash -n scripts/verify`, and `git diff --cached --check` passed before commit. A shared integration gate was active after the merge, so the post-merge fast gate is queued behind it.
Author
Owner

Starting recopy-plan #46. Worktree: /mnt/hdd/infraternal/wt-lp/recopy-plan (detached at 456cee5a84); target branch is calternal-port. I am inventorying the calternal 6440a5f..c4a61e8cf diff and mapping it onto the infraternal copies. Outputs will be limited to /mnt/hdd/infraternal/jobs/recopy-plan/recopy.patch and recopy.md; no source files will be applied here.

Starting recopy-plan #46. Worktree: /mnt/hdd/infraternal/wt-lp/recopy-plan (detached at 456cee5a8421657a64e6f2d86eea671854141ef8); target branch is calternal-port. I am inventorying the calternal 6440a5f..c4a61e8cf diff and mapping it onto the infraternal copies. Outputs will be limited to /mnt/hdd/infraternal/jobs/recopy-plan/recopy.patch and recopy.md; no source files will be applied here.
Author
Owner

Evidence from calternal c4a61e8cf for the recopy choices:

  • docs/DESIGN.md §34 says the Inspector belongs in the Tab Bar morph and supersedes the earlier anchored popover; current packages/ui/src/components/Inspector.svelte still renders PopoverSurface. This leaves the Inspector presentation unresolved for the port.
  • docs/DESIGN.md §32 S11 specifies a 640px compact palette below 960px and clamp(640px, 62vw, 1100px) for full results at 960px and wider. apps/web/src/lib/components/search-dialog.svelte transitions width and max-height; the infraternal motion budget permits transform/opacity only, so those layout transitions need adaptation.
  • docs/DESIGN.md §34/§35 and packages/ui/src/tokens.css set shared glass tint to 78% light / 30% dark, 85% light chrome, 16px blur, and 1.8/1.5 saturation. Settings-row docs specify alignment but do not state a no-divider rule; current SettingsRow.svelte draws no row border.
Evidence from calternal c4a61e8cf for the recopy choices: - `docs/DESIGN.md` §34 says the Inspector belongs in the Tab Bar morph and supersedes the earlier anchored popover; current `packages/ui/src/components/Inspector.svelte` still renders `PopoverSurface`. This leaves the Inspector presentation unresolved for the port. - `docs/DESIGN.md` §32 S11 specifies a 640px compact palette below 960px and `clamp(640px, 62vw, 1100px)` for full results at 960px and wider. `apps/web/src/lib/components/search-dialog.svelte` transitions `width` and `max-height`; the infraternal motion budget permits transform/opacity only, so those layout transitions need adaptation. - `docs/DESIGN.md` §34/§35 and `packages/ui/src/tokens.css` set shared glass tint to 78% light / 30% dark, 85% light chrome, 16px blur, and 1.8/1.5 saturation. Settings-row docs specify alignment but do not state a no-divider rule; current `SettingsRow.svelte` draws no row border.
Author
Owner

Continuation on GPT 6.1 Sol: branch calternal-port, head 456cee5a8421657a64e6f2d86eea671854141ef8, original base 4870b301b789840f6ae5d69d13756b9197f25d10. Worktree is clean; reviewed progress and latest dev merge. Post-merge scripts/verify fast is running. Integration and browser remain serialized and require load5 < 8.

Browser harness finding: chromium.launch() uses Playwright defaults, including --disable-back-forward-cache, but the lifecycle acceptance requires real persisted pagehide/pageshow. Removed that single default argument for the app browser gate. Upstream evidence: https://github.com/microsoft/playwright/blob/main/packages/playwright-core/src/server/chromium/chromiumSwitches.ts . No lifecycle assertion weakened.

Continuation on GPT 6.1 Sol: branch `calternal-port`, head `456cee5a8421657a64e6f2d86eea671854141ef8`, original base `4870b301b789840f6ae5d69d13756b9197f25d10`. Worktree is clean; reviewed progress and latest dev merge. Post-merge `scripts/verify fast` is running. Integration and browser remain serialized and require load5 < 8. Browser harness finding: `chromium.launch()` uses Playwright defaults, including `--disable-back-forward-cache`, but the lifecycle acceptance requires real persisted pagehide/pageshow. Removed that single default argument for the app browser gate. Upstream evidence: https://github.com/microsoft/playwright/blob/main/packages/playwright-core/src/server/chromium/chromiumSwitches.ts . No lifecycle assertion weakened.
Author
Owner

recopy-plan continuation: detached worktree at 456cee5a8421657a64e6f2d86eea671854141ef8; current calternal-port resolves to the same head. Preparing patch artifacts only for calternal 6440a5f..c4a61e8cf; no source-tree edits, nested jobs, pushes, or source-clone modifications. Full copied-file inventory and source deltas are being recorded. Current source docs conflict with the requested narrow search and 1.035 tap, and specify an Inspector Tab Bar morph; those differences will be recorded for the owner.

recopy-plan continuation: detached worktree at `456cee5a8421657a64e6f2d86eea671854141ef8`; current `calternal-port` resolves to the same head. Preparing patch artifacts only for calternal `6440a5f..c4a61e8cf`; no source-tree edits, nested jobs, pushes, or source-clone modifications. Full copied-file inventory and source deltas are being recorded. Current source docs conflict with the requested narrow search and 1.035 tap, and specify an Inspector Tab Bar morph; those differences will be recorded for the owner.
Author
Owner

recopy-plan findings at calternal c4a61e8cf:

  • DESIGN §34 #588 specifies light overlay/card tint 78%, chrome 85%, blur 16px, saturation 1.8 and brightness 1.05; the current tokens implement these roles.
  • DESIGN §32 S11 specifies clamp(640px, 62vw, 1100px) on wide screens; search-dialog.svelte describes Raycast/Spotlight but retains that wide preview layout. The brief's narrow palette and blur-only-on-action-pills are target requirements, not current source-doc rules.
  • DESIGN §34 #425 specifies a 1.05 pulse with dip/settle, rather than the brief's 1.035 peak. The candidate retains a 1.035 peak and removes undershoot.
  • DESIGN §34 #583 specifies a Tab Bar Inspector morph, but current Inspector.svelte still uses PopoverSurface, an anchored popover and phone sheet. Infraternal does not ship an Inspector/bottom mode tray; candidate leaves detail routes intact pending an owner decision.
  • Current SettingRow.svelte still has border-bottom: 1px solid var(--hair); no no-divider requirement was found in current DESIGN/CLAUDE docs. Candidate follows the brief and removes dividers.
  • Source Menu has touch drill-in, trailing checks, aligned icon/shortcut columns and shared active hover/focus state. Candidate carries those behaviors, preserving target registry, lazy shell imports, local appearance storage and compositor-only motion.

Current target advanced from 456cee5 to d486c60b413305e292d2c1fceaeb8cab9b07dee4; those changes are verify/browser evidence only. Disposable candidate now uses that head. Candidate svelte-check: svelte-check found 0 errors and 0 warnings; UI Vitest: Test Files 3 passed (3), Tests 9 passed (9). Fast gate is in progress. No real-browser visual claim is made by this read-only planning job.

recopy-plan findings at calternal `c4a61e8cf`: - DESIGN §34 #588 specifies light overlay/card tint 78%, chrome 85%, blur 16px, saturation 1.8 and brightness 1.05; the current tokens implement these roles. - DESIGN §32 S11 specifies `clamp(640px, 62vw, 1100px)` on wide screens; `search-dialog.svelte` describes Raycast/Spotlight but retains that wide preview layout. The brief's narrow palette and blur-only-on-action-pills are target requirements, not current source-doc rules. - DESIGN §34 #425 specifies a 1.05 pulse with dip/settle, rather than the brief's 1.035 peak. The candidate retains a 1.035 peak and removes undershoot. - DESIGN §34 #583 specifies a Tab Bar Inspector morph, but current `Inspector.svelte` still uses `PopoverSurface`, an anchored popover and phone sheet. Infraternal does not ship an Inspector/bottom mode tray; candidate leaves detail routes intact pending an owner decision. - Current `SettingRow.svelte` still has `border-bottom: 1px solid var(--hair)`; no no-divider requirement was found in current DESIGN/CLAUDE docs. Candidate follows the brief and removes dividers. - Source Menu has touch drill-in, trailing checks, aligned icon/shortcut columns and shared active hover/focus state. Candidate carries those behaviors, preserving target registry, lazy shell imports, local appearance storage and compositor-only motion. Current target advanced from `456cee5` to `d486c60b413305e292d2c1fceaeb8cab9b07dee4`; those changes are verify/browser evidence only. Disposable candidate now uses that head. Candidate svelte-check: `svelte-check found 0 errors and 0 warnings`; UI Vitest: `Test Files 3 passed (3)`, `Tests 9 passed (9)`. Fast gate is in progress. No real-browser visual claim is made by this read-only planning job.
Author
Owner

Clean post-merge fast gate on calternal-port head d486c60: exit 0, all 16 checks passed. The earlier attempt was discarded because I edited the verifier while it ran; no product source changed between the attempts. Heavy integration/browser remain queued until load5 < 8 and no shared heavy gate.

WARN load5=17.75 exceeds online CPU count=8; timing-sensitive checks may be delayed
PASS fast: migrations are append-only (0.250s)
PASS fast: workspace package dependencies (0.220s)
PASS fast: JavaScript dependencies (0.018s)
PASS fast: build web app (9.783s)
PASS fast: cargo fmt --check (1.139s)
PASS fast: cargo clippy (16.505s)
PASS fast: cargo test (103.370s)
PASS fast: svelte-check (10.155s)
PASS fast: UI package svelte-check (3.419s)
PASS fast: stream package typecheck (4.027s)
PASS fast: Vitest (3.137s)
PASS fast: UI package Vitest (2.790s)
PASS fast: stream package Vitest (1.011s)
PASS fast: OpenAPI and TypeScript client drift (27.101s)
PASS fast: terminal TypeScript (4.854s)
PASS fast: terminal Vitest (1.979s)
Clean post-merge fast gate on `calternal-port` head `d486c60`: exit 0, all 16 checks passed. The earlier attempt was discarded because I edited the verifier while it ran; no product source changed between the attempts. Heavy integration/browser remain queued until load5 < 8 and no shared heavy gate. ```text WARN load5=17.75 exceeds online CPU count=8; timing-sensitive checks may be delayed PASS fast: migrations are append-only (0.250s) PASS fast: workspace package dependencies (0.220s) PASS fast: JavaScript dependencies (0.018s) PASS fast: build web app (9.783s) PASS fast: cargo fmt --check (1.139s) PASS fast: cargo clippy (16.505s) PASS fast: cargo test (103.370s) PASS fast: svelte-check (10.155s) PASS fast: UI package svelte-check (3.419s) PASS fast: stream package typecheck (4.027s) PASS fast: Vitest (3.137s) PASS fast: UI package Vitest (2.790s) PASS fast: stream package Vitest (1.011s) PASS fast: OpenAPI and TypeScript client drift (27.101s) PASS fast: terminal TypeScript (4.854s) PASS fast: terminal Vitest (1.979s) ```
Author
Owner

Platform isolation for the persisted lifecycle acceptance: a two-page localhost document test with the default Chromium headless shell and BFCache disabling argument removed yielded events: [false], with masked non-restoration reasons. The same test using channel: chromium and goBack({waitUntil: commit}) yielded events: [false, true] and notRestoredReasons: null. A load-wait on the real restore timed out (no new load event); the product harness already correctly waits for commit.

Selected the full Chromium headless channel for the app browser gate, retaining the strict persisted lifecycle assertion. Official documentation distinguishes the separate headless shell from the full Chromium channel: https://playwright.dev/docs/browsers . Viewport captures now default to exactly the active viewport, including device and mobile route plates. Node syntax and git whitespace checks pass.

Platform isolation for the persisted lifecycle acceptance: a two-page localhost document test with the default Chromium headless shell and BFCache disabling argument removed yielded `events: [false]`, with masked non-restoration reasons. The same test using `channel: chromium` and `goBack({waitUntil: commit})` yielded `events: [false, true]` and `notRestoredReasons: null`. A load-wait on the real restore timed out (no new load event); the product harness already correctly waits for commit. Selected the full Chromium headless channel for the app browser gate, retaining the strict persisted lifecycle assertion. Official documentation distinguishes the separate headless shell from the full Chromium channel: https://playwright.dev/docs/browsers . Viewport captures now default to exactly the active viewport, including device and mobile route plates. Node syntax and git whitespace checks pass.
Author
Owner

Lifecycle failure-injection finding: a synchronous request factory / stream.open failure removes the registration but did not invoke the idle retirement path. A failing-first Vitest regression observed zero socket close calls after the 5-second grace. The catch path now invokes closeWhenIdle after removing the owner.

Targeted verification: stream attachment lifecycle tests 3/3 pass (failed request retirement, quick-hop transport reuse then last detach, immediate pagehide/persisted pageshow reopen). Web Svelte check: 0 errors, 0 warnings. Git diff whitespace check passes. Full fast rerun next; integration/browser still queued on load5 > 8.

Lifecycle failure-injection finding: a synchronous request factory / stream.open failure removes the registration but did not invoke the idle retirement path. A failing-first Vitest regression observed zero socket close calls after the 5-second grace. The catch path now invokes closeWhenIdle after removing the owner. Targeted verification: stream attachment lifecycle tests 3/3 pass (failed request retirement, quick-hop transport reuse then last detach, immediate pagehide/persisted pageshow reopen). Web Svelte check: 0 errors, 0 warnings. Git diff whitespace check passes. Full fast rerun next; integration/browser still queued on load5 > 8.
Author
Owner

Fast gate on calternal-port head 7e887e7: exit 0, all 16 stages passed, including the new attachment lifecycle failure-injection tests. Integration and browser remain pending: latest preflight load5 13.22; no heavy gate will start above the requested threshold.

WARN load5=13.21 exceeds online CPU count=8; timing-sensitive checks may be delayed
PASS fast: migrations are append-only (0.271s)
PASS fast: workspace package dependencies (0.293s)
PASS fast: JavaScript dependencies (0.010s)
PASS fast: build web app (15.377s)
PASS fast: cargo fmt --check (1.676s)
PASS fast: cargo clippy (24.601s)
PASS fast: cargo test (138.616s)
PASS fast: svelte-check (10.852s)
PASS fast: UI package svelte-check (4.490s)
PASS fast: stream package typecheck (4.673s)
PASS fast: Vitest (3.982s)
PASS fast: UI package Vitest (3.570s)
PASS fast: stream package Vitest (0.939s)
PASS fast: OpenAPI and TypeScript client drift (23.089s)
PASS fast: terminal TypeScript (2.446s)
PASS fast: terminal Vitest (1.281s)
Fast gate on `calternal-port` head `7e887e7`: exit 0, all 16 stages passed, including the new attachment lifecycle failure-injection tests. Integration and browser remain pending: latest preflight load5 13.22; no heavy gate will start above the requested threshold. ```text WARN load5=13.21 exceeds online CPU count=8; timing-sensitive checks may be delayed PASS fast: migrations are append-only (0.271s) PASS fast: workspace package dependencies (0.293s) PASS fast: JavaScript dependencies (0.010s) PASS fast: build web app (15.377s) PASS fast: cargo fmt --check (1.676s) PASS fast: cargo clippy (24.601s) PASS fast: cargo test (138.616s) PASS fast: svelte-check (10.852s) PASS fast: UI package svelte-check (4.490s) PASS fast: stream package typecheck (4.673s) PASS fast: Vitest (3.982s) PASS fast: UI package Vitest (3.570s) PASS fast: stream package Vitest (0.939s) PASS fast: OpenAPI and TypeScript client drift (23.089s) PASS fast: terminal TypeScript (2.446s) PASS fast: terminal Vitest (1.281s) ```
Author
Owner

recopy-plan complete: patch/report artifacts only; no application, source edits, commits, pushes, merges or nested jobs.

  • Detached job HEAD: 456cee5a8421657a64e6f2d86eea671854141ef8 (unchanged).
  • Current calternal-port checked base: 7e887e7f5aaab43c930db7ca4cf4dd1d616c2c10. Later browser and stream-attachment changes from port-final were preserved; neither stream implementation nor its new tests occur in the patch.
  • Source range: calternal 6440a5f8382794f423847c07b98adfa4852a398d..c4a61e8cf090170f35b1bed3350d9de20c83ecd5.
  • Artifacts: /mnt/hdd/infraternal/jobs/recopy-plan/recopy.patch and recopy.md. Full copied-file inventory and source range diff: inventory.json, upstream.patch in the same directory. 69 copied/adapted mappings; candidate patch has 52 files and 223 hunks, each indexed in the report, including binary font updates.
  • Patch SHA-256: 99dbb2a14dac7aad51b78a2e1182e5e24f38ac2454c26a9b854498516392474b.

Candidate: current shared Light glass/36 palettes/type roles; current aligned menus, trailing checks and touch drill-in; compatible primitives/tooltips; centered narrow 640px navigation search with blur only on action pills; 1.035 tap returning to 1; no settings row dividers. Preserves target routes/feature scope, lazy shell imports, local palette-id preference, sidebar operations and stream lifecycle. Removes source dimension/paint animations and retains immediate keyboard/reduced-motion behavior. Browser appearance test selectors adapt to the family Menu without removing persistence assertions.

Owner choices are explicit in recopy.md: Inspector Tab Bar morph (current docs) versus anchored popover/sheet (current code); narrow 640px search (brief) versus source desktop 1100px preview search. Current docs/source also specify a 1.05 tap with settle and retain row dividers; the candidate intentionally follows this brief on those points. No placeholder Inspector, bottom tray, preview API, font catalog or calternal-only routes were introduced.

Final clean temporary-copy check (then deleted, patch never applied):

Base: 7e887e7f5aaab43c930db7ca4cf4dd1d616c2c10
Command: git apply --check /mnt/hdd/infraternal/jobs/recopy-plan/recopy.patch
Exit: 0

Both targeted Svelte checks:

svelte-check found 0 errors and 0 warnings

Final targeted frontend suites:

 Test Files  13 passed (13)
      Tests  67 passed (67)
 Test Files  3 passed (3)
      Tests  10 passed (10)

Focused server-unit diagnostic:

test result: ok. 52 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 2.90s

Fast is not green; this artifact is not a merge signal. Initial fast passed Rust and web checks, then caught two UI-package DOM-iteration errors, fixed using Array.from. The second fast stopped at Rust workspace tests (exit 101); the first 240 test-output lines retained by verify do not include the exact failing test. That failure remains unresolved and is not attributed to load without evidence. Rust source is unchanged. Targeted frontend checks/suites passed separately after the fixes and current-target reconciliation. Final fast output verbatim:

WARN load5=12.10 exceeds online CPU count=8; timing-sensitive checks may be delayed
PASS fast: migrations are append-only (0.295s)
PASS fast: workspace package dependencies (0.240s)
PASS fast: JavaScript dependencies (0.005s)
PASS fast: build web app (17.107s)
PASS fast: cargo fmt --check (2.048s)
PASS fast: cargo clippy (20.185s)
FAIL fast: cargo test (85.995s)

Full logs are alongside the artifacts. Production browser screenshots, visual glass/contrast, Safari/iOS, bundle/performance and merge verification remain unverified; no browser/integration/bench gate was run. Implementation approval/application must be followed by the required verification loop. All owned disposable checkouts are deleted; the real worktree remains clean. Issue left open.

recopy-plan complete: **patch/report artifacts only; no application, source edits, commits, pushes, merges or nested jobs.** - Detached job HEAD: `456cee5a8421657a64e6f2d86eea671854141ef8` (unchanged). - Current `calternal-port` checked base: `7e887e7f5aaab43c930db7ca4cf4dd1d616c2c10`. Later browser and stream-attachment changes from port-final were preserved; neither stream implementation nor its new tests occur in the patch. - Source range: calternal `6440a5f8382794f423847c07b98adfa4852a398d..c4a61e8cf090170f35b1bed3350d9de20c83ecd5`. - Artifacts: `/mnt/hdd/infraternal/jobs/recopy-plan/recopy.patch` and `recopy.md`. Full copied-file inventory and source range diff: `inventory.json`, `upstream.patch` in the same directory. 69 copied/adapted mappings; candidate patch has 52 files and 223 hunks, each indexed in the report, including binary font updates. - Patch SHA-256: `99dbb2a14dac7aad51b78a2e1182e5e24f38ac2454c26a9b854498516392474b`. Candidate: current shared Light glass/36 palettes/type roles; current aligned menus, trailing checks and touch drill-in; compatible primitives/tooltips; centered narrow 640px navigation search with blur only on action pills; 1.035 tap returning to 1; no settings row dividers. Preserves target routes/feature scope, lazy shell imports, local palette-id preference, sidebar operations and stream lifecycle. Removes source dimension/paint animations and retains immediate keyboard/reduced-motion behavior. Browser appearance test selectors adapt to the family Menu without removing persistence assertions. Owner choices are explicit in recopy.md: Inspector Tab Bar morph (current docs) versus anchored popover/sheet (current code); narrow 640px search (brief) versus source desktop 1100px preview search. Current docs/source also specify a 1.05 tap with settle and retain row dividers; the candidate intentionally follows this brief on those points. No placeholder Inspector, bottom tray, preview API, font catalog or calternal-only routes were introduced. Final clean temporary-copy check (then deleted, patch never applied): ```text Base: 7e887e7f5aaab43c930db7ca4cf4dd1d616c2c10 Command: git apply --check /mnt/hdd/infraternal/jobs/recopy-plan/recopy.patch Exit: 0 ``` Both targeted Svelte checks: ```text svelte-check found 0 errors and 0 warnings ``` Final targeted frontend suites: ```text Test Files 13 passed (13) Tests 67 passed (67) Test Files 3 passed (3) Tests 10 passed (10) ``` Focused server-unit diagnostic: ```text test result: ok. 52 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 2.90s ``` **Fast is not green; this artifact is not a merge signal.** Initial fast passed Rust and web checks, then caught two UI-package DOM-iteration errors, fixed using Array.from. The second fast stopped at Rust workspace tests (exit 101); the first 240 test-output lines retained by verify do not include the exact failing test. That failure remains unresolved and is not attributed to load without evidence. Rust source is unchanged. Targeted frontend checks/suites passed separately after the fixes and current-target reconciliation. Final fast output verbatim: ```text WARN load5=12.10 exceeds online CPU count=8; timing-sensitive checks may be delayed PASS fast: migrations are append-only (0.295s) PASS fast: workspace package dependencies (0.240s) PASS fast: JavaScript dependencies (0.005s) PASS fast: build web app (17.107s) PASS fast: cargo fmt --check (2.048s) PASS fast: cargo clippy (20.185s) FAIL fast: cargo test (85.995s) ``` Full logs are alongside the artifacts. Production browser screenshots, visual glass/contrast, Safari/iOS, bundle/performance and merge verification remain unverified; no browser/integration/bench gate was run. Implementation approval/application must be followed by the required verification loop. All owned disposable checkouts are deleted; the real worktree remains clean. Issue left open.
Author
Owner

Orchestrator note on recopy.patch: it copies calternal's current Light glass at 78% opacity (from calternal #588). The owner rejected exactly that change in calternal ('why did you make it so opaque?'). Owner rule: Light glass stays clearly translucent, like Dark at about 30% tint; contrast comes from text roles, blur and saturation, never from raising opacity. Pick the most translucent alpha that passes the glass contrast audit. Whoever applies the patch must override the Light glass alpha accordingly; everything else copies as-is.

Orchestrator note on recopy.patch: it copies calternal's current Light glass at **78% opacity** (from calternal #588). **The owner rejected exactly that change in calternal** ('why did you make it so opaque?'). Owner rule: Light glass stays clearly translucent, like Dark at about 30% tint; contrast comes from text roles, blur and saturation, never from raising opacity. Pick the most translucent alpha that passes the glass contrast audit. Whoever applies the patch must override the Light glass alpha accordingly; everything else copies as-is.
Author
Owner

Restoration race fixed: a retired StreamClient retains its WebSocket onclose callback, so that callback can publish closed after persisted pageshow creates a live replacement. The failure-injection restoration test failed first (expected live, received closed) when the old transport emitted its delayed close. State publication now checks that the emitting transport is the currently owned client.

The same lifecycle tests pass 3/3 after the fix; Svelte check reports 0 errors and 0 warnings; whitespace check passes. Full fast is rerunning on the new head. Heavy integration/browser remain queued; load5 15.64 at 20:00 local.

Restoration race fixed: a retired StreamClient retains its WebSocket onclose callback, so that callback can publish closed after persisted pageshow creates a live replacement. The failure-injection restoration test failed first (`expected live, received closed`) when the old transport emitted its delayed close. State publication now checks that the emitting transport is the currently owned client. The same lifecycle tests pass 3/3 after the fix; Svelte check reports 0 errors and 0 warnings; whitespace check passes. Full fast is rerunning on the new head. Heavy integration/browser remain queued; load5 15.64 at 20:00 local.
Author
Owner

Fast run after c2710f8 was interrupted during workspace Rust tests: verifier returned exit 143 (SIGTERM), and its log ends after Clippy PASS with no test assertion diagnostic. I did not signal this run. Its log is /tmp/port-final-sol-fast-retired.log; targeted lifecycle tests 3/3 and web Svelte check remain passing. A clean full fast rerun is required. Latest load5 14.35; integration/browser remain queued under the required host-load threshold.

Fast run after `c2710f8` was interrupted during workspace Rust tests: verifier returned exit 143 (SIGTERM), and its log ends after Clippy PASS with no test assertion diagnostic. I did not signal this run. Its log is `/tmp/port-final-sol-fast-retired.log`; targeted lifecycle tests 3/3 and web Svelte check remain passing. A clean full fast rerun is required. Latest load5 14.35; integration/browser remain queued under the required host-load threshold.
Author
Owner

Orchestrator: at about 23:30 IST, job lp-flaky mistakenly sent SIGTERM to another job's scripts/verify fast (PID 1341778). Any job whose verify fast ended with 'Terminated' or exit 143 around then must rerun it; it is not a real failure.

Orchestrator: at about 23:30 IST, job lp-flaky mistakenly sent SIGTERM to another job's `scripts/verify fast` (PID 1341778). **Any job whose `verify fast` ended with 'Terminated' or exit 143 around then must rerun it; it is not a real failure.**
Author
Owner

Clean fast retry on c2710f8 returned 101 at cargo workspace tests. The verifier printed only its first 240 output lines, ending partway through the server unit tests; it omitted the actual failing test/assertion. This is an unclassified failure, not attributed to host load. Updated the existing verifier to retain the final 100 lines on long non-browser failures as well as the initial window; shell syntax and whitespace checks pass. Next rerun will capture the exact failure. Log /tmp/port-final-sol-fast-retired-retry.log.

Clean fast retry on `c2710f8` returned 101 at cargo workspace tests. The verifier printed only its first 240 output lines, ending partway through the server unit tests; it omitted the actual failing test/assertion. This is an unclassified failure, not attributed to host load. Updated the existing verifier to retain the final 100 lines on long non-browser failures as well as the initial window; shell syntax and whitespace checks pass. Next rerun will capture the exact failure. Log `/tmp/port-final-sol-fast-retired-retry.log`.
Author
Owner

Failure tail captured the exact fast blocker: database_wal_and_backup_are_private_and_reject_substitution, crates/server/tests/private_storage.rs:49, failed creating its own WAL-sidecar symlink with OS AlreadyExists. The fixture uses a unique TempDir, so this is not a cross-job path collision.

Source trace: backup() opens a dedicated SQLite connection outside the pool and drops it after VACUUM INTO. SQLx 0.8.6 explicit close awaits worker shutdown; pool.close() cannot close that independent connection. Testing an explicit connection.close().await on both VACUUM success/failure before returning (preserving the original VACUUM error precedence). Existing permission/link rejection assertions are unchanged; this remains a hypothesis until the real SQLite regression and full gate rerun pass. Sources: https://docs.rs/sqlx/0.8.6/sqlx/trait.Connection.html#tymethod.close and https://github.com/transact-rs/sqlx/blob/v0.8.6/sqlx-sqlite/src/connection/mod.rs .

Failure tail captured the exact fast blocker: `database_wal_and_backup_are_private_and_reject_substitution`, crates/server/tests/private_storage.rs:49, failed creating its own WAL-sidecar symlink with OS AlreadyExists. The fixture uses a unique TempDir, so this is not a cross-job path collision. Source trace: backup() opens a dedicated SQLite connection outside the pool and drops it after VACUUM INTO. SQLx 0.8.6 explicit close awaits worker shutdown; pool.close() cannot close that independent connection. Testing an explicit connection.close().await on both VACUUM success/failure before returning (preserving the original VACUUM error precedence). Existing permission/link rejection assertions are unchanged; this remains a hypothesis until the real SQLite regression and full gate rerun pass. Sources: https://docs.rs/sqlx/0.8.6/sqlx/trait.Connection.html#tymethod.close and https://github.com/transact-rs/sqlx/blob/v0.8.6/sqlx-sqlite/src/connection/mod.rs .
Author
Owner

The dedicated-backup close hypothesis was disproved: the unchanged regression passed once, then immediately reproduced AlreadyExists in repetition. Discarded my uncommitted storage implementation/docs edits; production storage is unchanged.

Fixed the fixture setup instead: after closing its own storage, inspect the fixture WAL path. If present, assert it is a regular 0600 file and remove only that fixture-owned file before creating the substituted symlink. All existing permissions, destination overwrite/link refusal, sidecar-link rejection, database-link rejection and directory-alias rejection assertions remain. This test is about substitution refusal, not SQLite unlink timing. SQLite documentation describes WAL files as quasi-persistent: https://www.sqlite.org/wal.html .

Targeted real SQLite test passed, then the compiled test passed 20 consecutive runs with the fixture correction. No test assertion was removed. Next full fast run will verify the workspace.

Visual capture finding also corrected: C2 used Noir while references use Midnight and mobile captures used fine-pointer tokens. The capture helper now uses Midnight and pointer-aware touch emulation; desktop workspace interaction restores fine-pointer mode. Node syntax and whitespace checks pass. Preliminary plates (52, older captures; not final approval): /mnt/hdd/infraternal/artifacts/port-final/sol-preliminary-plates .

The dedicated-backup close hypothesis was disproved: the unchanged regression passed once, then immediately reproduced AlreadyExists in repetition. Discarded my uncommitted storage implementation/docs edits; production storage is unchanged. Fixed the fixture setup instead: after closing its own storage, inspect the fixture WAL path. If present, assert it is a regular 0600 file and remove only that fixture-owned file before creating the substituted symlink. All existing permissions, destination overwrite/link refusal, sidecar-link rejection, database-link rejection and directory-alias rejection assertions remain. This test is about substitution refusal, not SQLite unlink timing. SQLite documentation describes WAL files as quasi-persistent: https://www.sqlite.org/wal.html . Targeted real SQLite test passed, then the compiled test passed 20 consecutive runs with the fixture correction. No test assertion was removed. Next full fast run will verify the workspace. Visual capture finding also corrected: C2 used Noir while references use Midnight and mobile captures used fine-pointer tokens. The capture helper now uses Midnight and pointer-aware touch emulation; desktop workspace interaction restores fine-pointer mode. Node syntax and whitespace checks pass. Preliminary plates (52, older captures; not final approval): /mnt/hdd/infraternal/artifacts/port-final/sol-preliminary-plates .
Author
Owner

Continuation verification on b126700: corrected private-storage WAL fixture passed 20 repetitions; full fast gate exit 0. Production credential storage is unchanged.

WARN load5=8.91 exceeds online CPU count=8; timing-sensitive checks may be delayed
PASS fast: migrations are append-only (0.144s)
PASS fast: workspace package dependencies (0.263s)
PASS fast: JavaScript dependencies (0.007s)
PASS fast: build web app (7.568s)
PASS fast: cargo fmt --check (0.958s)
PASS fast: cargo clippy (16.140s)
PASS fast: cargo test (114.395s)
PASS fast: svelte-check (9.744s)
PASS fast: UI package svelte-check (3.847s)
PASS fast: stream package typecheck (4.024s)
PASS fast: Vitest (3.342s)
PASS fast: UI package Vitest (3.660s)
PASS fast: stream package Vitest (1.243s)
PASS fast: OpenAPI and TypeScript client drift (27.336s)
PASS fast: terminal TypeScript (2.284s)
PASS fast: terminal Vitest (1.495s)

Preliminary plate inspection identified native list markers in the lazy interactive sidebar because list resets belonged to the static component’s scoped CSS. Moving those resets into shared SidebarChrome and adding browser geometry coverage before final capture.

Continuation verification on `b126700`: corrected private-storage WAL fixture passed 20 repetitions; full fast gate exit 0. Production credential storage is unchanged. ```text WARN load5=8.91 exceeds online CPU count=8; timing-sensitive checks may be delayed PASS fast: migrations are append-only (0.144s) PASS fast: workspace package dependencies (0.263s) PASS fast: JavaScript dependencies (0.007s) PASS fast: build web app (7.568s) PASS fast: cargo fmt --check (0.958s) PASS fast: cargo clippy (16.140s) PASS fast: cargo test (114.395s) PASS fast: svelte-check (9.744s) PASS fast: UI package svelte-check (3.847s) PASS fast: stream package typecheck (4.024s) PASS fast: Vitest (3.342s) PASS fast: UI package Vitest (3.660s) PASS fast: stream package Vitest (1.243s) PASS fast: OpenAPI and TypeScript client drift (27.336s) PASS fast: terminal TypeScript (2.284s) PASS fast: terminal Vitest (1.495s) ``` Preliminary plate inspection identified native list markers in the lazy interactive sidebar because list resets belonged to the static component’s scoped CSS. Moving those resets into shared SidebarChrome and adding browser geometry coverage before final capture.
Author
Owner

8f52c03 fixes the native list bullets and indentation visible in preliminary desktop plates. Shared SidebarChrome now owns the list/section resets for both static and sortable navigation; no duplicate primitive added. Browser geometry assertions reject markers and nonzero list margin/padding, in addition to heading alignment, heading-local actions, no Infrastructure gap, and full-width selection. Svelte checking: 0 errors, 0 warnings. Fast rerun underway; serialized full browser gate queued with load5 < 8 and no competing heavy gate/release build.

`8f52c03` fixes the native list bullets and indentation visible in preliminary desktop plates. Shared SidebarChrome now owns the list/section resets for both static and sortable navigation; no duplicate primitive added. Browser geometry assertions reject markers and nonzero list margin/padding, in addition to heading alignment, heading-local actions, no Infrastructure gap, and full-width selection. Svelte checking: 0 errors, 0 warnings. Fast rerun underway; serialized full browser gate queued with load5 < 8 and no competing heavy gate/release build.
Author
Owner

Full fast gate on 8f52c03: exit 0, all 16 stages pass. Browser gate queued pending load5 < 8 and no competing heavy gate/release build.

PASS fast: migrations are append-only (0.244s)
PASS fast: workspace package dependencies (0.242s)
PASS fast: JavaScript dependencies (0.022s)
PASS fast: build web app (9.332s)
PASS fast: cargo fmt --check (1.111s)
PASS fast: cargo clippy (16.034s)
PASS fast: cargo test (125.767s)
PASS fast: svelte-check (9.581s)
PASS fast: UI package svelte-check (4.060s)
PASS fast: stream package typecheck (5.460s)
PASS fast: Vitest (4.605s)
PASS fast: UI package Vitest (4.644s)
PASS fast: stream package Vitest (1.399s)
PASS fast: OpenAPI and TypeScript client drift (24.774s)
PASS fast: terminal TypeScript (2.470s)
PASS fast: terminal Vitest (1.266s)
Full fast gate on `8f52c03`: exit 0, all 16 stages pass. Browser gate queued pending load5 < 8 and no competing heavy gate/release build. ```text PASS fast: migrations are append-only (0.244s) PASS fast: workspace package dependencies (0.242s) PASS fast: JavaScript dependencies (0.022s) PASS fast: build web app (9.332s) PASS fast: cargo fmt --check (1.111s) PASS fast: cargo clippy (16.034s) PASS fast: cargo test (125.767s) PASS fast: svelte-check (9.581s) PASS fast: UI package svelte-check (4.060s) PASS fast: stream package typecheck (5.460s) PASS fast: Vitest (4.605s) PASS fast: UI package Vitest (4.644s) PASS fast: stream package Vitest (1.399s) PASS fast: OpenAPI and TypeScript client drift (24.774s) PASS fast: terminal TypeScript (2.470s) PASS fast: terminal Vitest (1.266s) ```
Author
Owner

Orchestrator, gate policy from 00:10 IST: with about 12 jobs running, waiting for 'no other scripts/verify run active' deadlocks. Jobs: run scripts/verify fast plus your targeted tests, then finish and report 'merge gate pending'. Do not wait for scripts/verify merge. The orchestrator runs merge gates centrally, one at a time, on ready branches.

Orchestrator, gate policy from 00:10 IST: with about 12 jobs running, waiting for 'no other scripts/verify run active' deadlocks. **Jobs: run `scripts/verify fast` plus your targeted tests, then finish and report 'merge gate pending'. Do not wait for `scripts/verify merge`.** The orchestrator runs merge gates centrally, one at a time, on ready branches.
Author
Owner

f0448f6: reproduced a second persisted-document callback race failing-first. A delayed old-channel CLOSE deleted the new attachment channel after pageshow (expected restored channel, received undefined). Channel callbacks now check transport and channel ownership before publishing OPEN/DATA/error/close or removing registrations; old connect completion cannot mark a replacement connected. Focused lifecycle tests 3/3 pass; Svelte checking 0 errors and 0 warnings. Full fast rerun underway. Red/green logs: /tmp/port-final-sol-retired-channel-{red,green}.log.

`f0448f6`: reproduced a second persisted-document callback race failing-first. A delayed old-channel CLOSE deleted the new attachment channel after pageshow (expected restored channel, received undefined). Channel callbacks now check transport and channel ownership before publishing OPEN/DATA/error/close or removing registrations; old connect completion cannot mark a replacement connected. Focused lifecycle tests 3/3 pass; Svelte checking 0 errors and 0 warnings. Full fast rerun underway. Red/green logs: /tmp/port-final-sol-retired-channel-{red,green}.log.
Author
Owner

Full fast gate on f0448f6: all16 stages PASS, exit0. This head includes restored transport/channel ownership guards, shared sidebar geometry, and touch-aware auth/C2 captures. Browser still serialized behind another release build.

PASS fast: migrations are append-only (0.219s)
PASS fast: workspace package dependencies (0.309s)
PASS fast: JavaScript dependencies (0.007s)
PASS fast: build web app (9.419s)
PASS fast: cargo fmt --check (0.918s)
PASS fast: cargo clippy (14.162s)
PASS fast: cargo test (123.743s)
PASS fast: svelte-check (11.169s)
PASS fast: UI package svelte-check (6.058s)
PASS fast: stream package typecheck (6.670s)
PASS fast: Vitest (6.196s)
PASS fast: UI package Vitest (4.403s)
PASS fast: stream package Vitest (1.043s)
PASS fast: OpenAPI and TypeScript client drift (25.857s)
PASS fast: terminal TypeScript (2.507s)
PASS fast: terminal Vitest (1.349s)
Full fast gate on `f0448f6`: all16 stages PASS, exit0. This head includes restored transport/channel ownership guards, shared sidebar geometry, and touch-aware auth/C2 captures. Browser still serialized behind another release build. ```text PASS fast: migrations are append-only (0.219s) PASS fast: workspace package dependencies (0.309s) PASS fast: JavaScript dependencies (0.007s) PASS fast: build web app (9.419s) PASS fast: cargo fmt --check (0.918s) PASS fast: cargo clippy (14.162s) PASS fast: cargo test (123.743s) PASS fast: svelte-check (11.169s) PASS fast: UI package svelte-check (6.058s) PASS fast: stream package typecheck (6.670s) PASS fast: Vitest (6.196s) PASS fast: UI package Vitest (4.403s) PASS fast: stream package Vitest (1.043s) PASS fast: OpenAPI and TypeScript client drift (25.857s) PASS fast: terminal TypeScript (2.507s) PASS fast: terminal Vitest (1.349s) ```
Author
Owner

Full browser gate started on f0448f6 after waiting for the competing release build. Start load5 ~3.7; no competing integration/browser/merge gate. Command uses CARGO_BUILD_JOBS=2, run id port-final-sol-browser-1, artifact base /mnt/hdd/infraternal/artifacts/port-final/sol-20261002. Dependencies and production web build passed; release binary compilation underway. Full log /tmp/port-final-sol-browser-1.log.

Full browser gate started on `f0448f6` after waiting for the competing release build. Start load5 ~3.7; no competing integration/browser/merge gate. Command uses CARGO_BUILD_JOBS=2, run id port-final-sol-browser-1, artifact base /mnt/hdd/infraternal/artifacts/port-final/sol-20261002. Dependencies and production web build passed; release binary compilation underway. Full log /tmp/port-final-sol-browser-1.log.
Author
Owner

Browser attempt1 on f0448f6 failed due to my auth capture ordering: helper persisted appearance on the initial about:blank document, producing a localStorage SecurityError. c81f406 establishes the real app origin before invoking the touch/theme helper. Node syntax and whitespace checks pass; no product source change. Full rerun queued behind the now-active competing merge gate.

Verbatim attempt1 output (exit1):

PASS browser: JavaScript dependencies (0.005s)
PASS browser: build web app (7.368s)
PASS browser: build release binary (300.663s)
PASS browser: install Chromium and system dependencies (3.731s)
PASS browser: terminal fixture Playwright (30.372s)
FAIL browser: Playwright against release server (1.693s)
error: evaluate: SecurityError: Failed to read the 'localStorage' property from 'Window': Access is denied for this document.
    at UtilityScript.evaluate (<anonymous>:313:16)
    at UtilityScript.<anonymous> (<anonymous>:1:44)
  log: [],

      at UtilityScript.evaluate (<anonymous>:313:16)
      at UtilityScript.<anonymous> (<anonymous>:1:44)
      at setC2CaptureTheme (/home/kayg/wt/calternal-port/scripts/browser-check.mjs:2903:14)
      at captureAuthScreenshots (/home/kayg/wt/calternal-port/scripts/browser-check.mjs:2122:9)
      at processTicksAndRejections (native:7:39)

Bun v1.4.2 (Linux x64)
Browser attempt1 on f0448f6 failed due to my auth capture ordering: helper persisted appearance on the initial about:blank document, producing a localStorage SecurityError. c81f406 establishes the real app origin before invoking the touch/theme helper. Node syntax and whitespace checks pass; no product source change. Full rerun queued behind the now-active competing merge gate. Verbatim attempt1 output (exit1): ```text PASS browser: JavaScript dependencies (0.005s) PASS browser: build web app (7.368s) PASS browser: build release binary (300.663s) PASS browser: install Chromium and system dependencies (3.731s) PASS browser: terminal fixture Playwright (30.372s) FAIL browser: Playwright against release server (1.693s) error: evaluate: SecurityError: Failed to read the 'localStorage' property from 'Window': Access is denied for this document. at UtilityScript.evaluate (<anonymous>:313:16) at UtilityScript.<anonymous> (<anonymous>:1:44) log: [], at UtilityScript.evaluate (<anonymous>:313:16) at UtilityScript.<anonymous> (<anonymous>:1:44) at setC2CaptureTheme (/home/kayg/wt/calternal-port/scripts/browser-check.mjs:2903:14) at captureAuthScreenshots (/home/kayg/wt/calternal-port/scripts/browser-check.mjs:2122:9) at processTicksAndRejections (native:7:39) Bun v1.4.2 (Linux x64) ```
Author
Owner

3f21598 adds explicit cold/static sidebar coverage before DnD lazy loading: move the pointer outside navigation before cold load, assert zero drag handles, then check heading alignment, list reset, heading-local actions, Infrastructure gap, and full-row selection. The existing interactive checks retain the same shared assertions. Node syntax and whitespace pass. Browser2 is queued behind an active competing merge gate and current load5 > 12. Product sources remain those that passed full fast on f0448f6.

`3f21598` adds explicit cold/static sidebar coverage before DnD lazy loading: move the pointer outside navigation before cold load, assert zero drag handles, then check heading alignment, list reset, heading-local actions, Infrastructure gap, and full-row selection. The existing interactive checks retain the same shared assertions. Node syntax and whitespace pass. Browser2 is queued behind an active competing merge gate and current load5 > 12. Product sources remain those that passed full fast on f0448f6.
Author
Owner

ae07848 fixes remaining early log/terminal capture mismatch: log captures previously changed media preference without named palette; terminal dark used Noir rather than pinned Midnight. Both now use existing shared theme/touch helper (without modifying stored appearance), restore Paper/fine-pointer desktop afterward. Node syntax and whitespace pass. Browser2 remains queued: last load5 9.48 and two other active merge verifiers PID1666660/PID1765042; this job has no active heavy gate. No other processes signalled or modified.

ae07848 fixes remaining early log/terminal capture mismatch: log captures previously changed media preference without named palette; terminal dark used Noir rather than pinned Midnight. Both now use existing shared theme/touch helper (without modifying stored appearance), restore Paper/fine-pointer desktop afterward. Node syntax and whitespace pass. Browser2 remains queued: last load5 9.48 and two other active merge verifiers PID1666660/PID1765042; this job has no active heavy gate. No other processes signalled or modified.
Author
Owner

Read the new central merge policy. This job will report merge gate pending for the orchestrator rather than running a local merge gate. The port-final brief explicitly requests full integration/browser and final visual plates; these remain pending. Browser2 is queued under this job’s no-heavy-overlap/load5<8 constraint. Current head ae07848, product fast and targeted tests green as recorded above.

Read the new central merge policy. This job will report merge gate pending for the orchestrator rather than running a local merge gate. The port-final brief explicitly requests full integration/browser and final visual plates; these remain pending. Browser2 is queued under this job’s no-heavy-overlap/load5<8 constraint. Current head ae07848, product fast and targeted tests green as recorded above.
Author
Owner

Browser2 started on ae07848 after the heavy gate/release queue cleared, start load5~4.1. Dependencies and production web build PASS; release compilation underway. This attempt includes all capture corrections (real-origin auth storage, Paper/Midnight palettes, pointer/touch geometry) and true cold/static sidebar assertions. Run id port-final-sol-browser-2; log /tmp/port-final-sol-browser-2.log; artifacts /mnt/hdd/infraternal/artifacts/port-final/sol-20261002/verify/port-final-sol-browser-2. Merge is orchestrator-owned under new policy.

Browser2 started on ae07848 after the heavy gate/release queue cleared, start load5~4.1. Dependencies and production web build PASS; release compilation underway. This attempt includes all capture corrections (real-origin auth storage, Paper/Midnight palettes, pointer/touch geometry) and true cold/static sidebar assertions. Run id port-final-sol-browser-2; log /tmp/port-final-sol-browser-2.log; artifacts /mnt/hdd/infraternal/artifacts/port-final/sol-20261002/verify/port-final-sol-browser-2. Merge is orchestrator-owned under new policy.
Author
Owner

Browser2 on ae07848 exit1. Release preparation and terminal fixture PASS; supported simultaneous tabs and pending-refresh sign-out PASS. Fallback second tab loses shell after two uncoordinated tabs rotate shared cookie concurrently (trace shows overlapping page5/page6 refresh requests and revoked-access401s). Docs/contracts.md §2.1 explicitly declares multi-tab unsupported when either coordination API is absent, and retains strict consumed-cookie family revocation.

d9f7c6b isolates each fallback case to one live document plus a real server refresh by another consumer; checks actual stale GET401 and200 retry of the SAME URL plus one notice. Supported two-tab and sign-out fence assertions retained. Product auth code/contract unchanged. Node syntax+whitespace pass; Browser3 queued for load5<8/noheavy/nootherrelease. Installed fullChromium probe: both documents remain visible after bringToFront; minimizing also leaves both visible. Primary API reference: https://playwright.dev/docs/api/class-page#page-bring-to-front. Platform observations are not product-gate passes.

Verbatim Browser2 output:

PASS browser: JavaScript dependencies (0.009s)
PASS browser: build web app (10.180s)
PASS browser: build release binary (402.978s)
PASS browser: install Chromium and system dependencies (4.644s)
PASS browser: terminal fixture Playwright (55.593s)
FAIL browser: Playwright against release server (32.455s)
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_401 context=main page=main-page-5 method=GET path=/api/v1/containers access_token_id=t_01M3Z2H5P19VXSQXJHJS9QMV7J
AUTH_401 context=main page=main-page-6 method=GET path=/api/v1/account access_token_id=t_01M3Z2H7CZZC3SNZNXGVT52FHH
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-4 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-4 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=main page=main-page-5 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-5 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=main page=main-page-5 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-5 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=main page=main-page-6 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-6 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=main page=main-page-6 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-5 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-5 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=main page=main-page-5 method=GET path=/api/v1/containers access_token_id=t_01M3Z2H5P19VXSQXJHJS9QMV7J
AUTH_REFRESH context=main page=main-page-6 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=main page=main-page-6 method=GET path=/api/v1/account access_token_id=t_01M3Z2H7CZZC3SNZNXGVT52FHH
8583 | 
8584 | // packages/utils/stackTrace.ts
8585 | function captureRawStack() {
8586 |   const stackTraceLimit = Error.stackTraceLimit;
8587 |   Error.stackTraceLimit = 50;
8588 |   const error = new Error();
                           ^
error: expect(locator).toHaveCount(expected) failed

Locator:  locator('.mode-header .mh-title')
Expected: 1
Received: 0
Timeout:  5000ms

Call log:
  - Expect "toHaveCount" locator('.mode-header .mh-title') with timeout 5000ms
  - waiting for locator('.mode-header .mh-title')
    13 × locator resolved to 0 elements
       - unexpected value "0"

 matcherResult: {
  actual: 0,
  expected: 1,
  message: "expect(locator).toHaveCount(expected) failed\n\nLocator:  locator('.mode-header .mh-title')\nExpected: 1\nReceived: 0\nTimeout:  5000ms\n\nCall log:\n  - Expect \"toHaveCount\" locator('.mode-header .mh-title') with timeout 5000ms\n  - waiting for locator('.mode-header .mh-title')\n    13 × locator resolved to 0 elements\n       - unexpected value \"0\"\n",
  name: "toHaveCount",
  pass: false,
  log: [ "  - Expect \"toHaveCount\" locator('.mode-header .mh-title') with timeout 5000ms",
    "  - waiting for locator('.mode-header .mh-title')", "    13 × locator resolved to 0 elements",
    "       - unexpected value \"0\""
  ],
  timeout: 5000,
  ariaSnapshot: undefined,
},

      at captureRawStack (/home/kayg/wt/calternal-port/node_modules/.bun/playwright-core@1.63.0/node_modules/playwright-core/lib/coreBundle.js:8588:21)
      at callMatcherAsStep (/home/kayg/wt/calternal-port/node_modules/.bun/playwright@1.63.0/node_modules/playwright/lib/matchers/expect.js:13310:57)
      at expectShellTitle (/home/kayg/wt/calternal-port/scripts/browser-check.mjs:595:28)
      at checkSharedCookieTabs (/home/kayg/wt/calternal-port/scripts/browser-check.mjs:2096:13)
      at processTicksAndRejections (native:7:39)

Bun v1.4.2 (Linux x64)
Browser2 on ae07848 exit1. Release preparation and terminal fixture PASS; supported simultaneous tabs and pending-refresh sign-out PASS. Fallback second tab loses shell after two uncoordinated tabs rotate shared cookie concurrently (trace shows overlapping page5/page6 refresh requests and revoked-access401s). Docs/contracts.md §2.1 explicitly declares multi-tab unsupported when either coordination API is absent, and retains strict consumed-cookie family revocation. d9f7c6b isolates each fallback case to one live document plus a real server refresh by another consumer; checks actual stale GET401 and200 retry of the SAME URL plus one notice. Supported two-tab and sign-out fence assertions retained. Product auth code/contract unchanged. Node syntax+whitespace pass; Browser3 queued for load5<8/noheavy/nootherrelease. Installed fullChromium probe: both documents remain visible after bringToFront; minimizing also leaves both visible. Primary API reference: https://playwright.dev/docs/api/class-page#page-bring-to-front. Platform observations are not product-gate passes. Verbatim Browser2 output: ```text PASS browser: JavaScript dependencies (0.009s) PASS browser: build web app (10.180s) PASS browser: build release binary (402.978s) PASS browser: install Chromium and system dependencies (4.644s) PASS browser: terminal fixture Playwright (55.593s) FAIL browser: Playwright against release server (32.455s) AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_401 context=main page=main-page-5 method=GET path=/api/v1/containers access_token_id=t_01M3Z2H5P19VXSQXJHJS9QMV7J AUTH_401 context=main page=main-page-6 method=GET path=/api/v1/account access_token_id=t_01M3Z2H7CZZC3SNZNXGVT52FHH AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401 AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401 AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401 AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401 AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401 AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401 AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401 AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401 AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401 AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-4 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-4 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=main page=main-page-5 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-5 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=main page=main-page-5 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-5 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=main page=main-page-6 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-6 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=main page=main-page-6 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-5 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-5 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=main page=main-page-5 method=GET path=/api/v1/containers access_token_id=t_01M3Z2H5P19VXSQXJHJS9QMV7J AUTH_REFRESH context=main page=main-page-6 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=main page=main-page-6 method=GET path=/api/v1/account access_token_id=t_01M3Z2H7CZZC3SNZNXGVT52FHH 8583 | 8584 | // packages/utils/stackTrace.ts 8585 | function captureRawStack() { 8586 | const stackTraceLimit = Error.stackTraceLimit; 8587 | Error.stackTraceLimit = 50; 8588 | const error = new Error(); ^ error: expect(locator).toHaveCount(expected) failed Locator: locator('.mode-header .mh-title') Expected: 1 Received: 0 Timeout: 5000ms Call log: - Expect "toHaveCount" locator('.mode-header .mh-title') with timeout 5000ms - waiting for locator('.mode-header .mh-title') 13 × locator resolved to 0 elements - unexpected value "0" matcherResult: { actual: 0, expected: 1, message: "expect(locator).toHaveCount(expected) failed\n\nLocator: locator('.mode-header .mh-title')\nExpected: 1\nReceived: 0\nTimeout: 5000ms\n\nCall log:\n - Expect \"toHaveCount\" locator('.mode-header .mh-title') with timeout 5000ms\n - waiting for locator('.mode-header .mh-title')\n 13 × locator resolved to 0 elements\n - unexpected value \"0\"\n", name: "toHaveCount", pass: false, log: [ " - Expect \"toHaveCount\" locator('.mode-header .mh-title') with timeout 5000ms", " - waiting for locator('.mode-header .mh-title')", " 13 × locator resolved to 0 elements", " - unexpected value \"0\"" ], timeout: 5000, ariaSnapshot: undefined, }, at captureRawStack (/home/kayg/wt/calternal-port/node_modules/.bun/playwright-core@1.63.0/node_modules/playwright-core/lib/coreBundle.js:8588:21) at callMatcherAsStep (/home/kayg/wt/calternal-port/node_modules/.bun/playwright@1.63.0/node_modules/playwright/lib/matchers/expect.js:13310:57) at expectShellTitle (/home/kayg/wt/calternal-port/scripts/browser-check.mjs:595:28) at checkSharedCookieTabs (/home/kayg/wt/calternal-port/scripts/browser-check.mjs:2096:13) at processTicksAndRejections (native:7:39) Bun v1.4.2 (Linux x64) ```
Author
Owner

Visual review of all eight fresh auth plates from Browser2 found the fixed mesh painting over auth heading, brand and fields, while positioned primitives remained visible. Real release-server probe confirmed the unpositioned wrapper (position:static), background z-index:0, and restored content with a positioning context. Diagnostic screenshots: /mnt/hdd/infraternal/artifacts/port-final/auth-stack-before.png and auth-stack-diagnostic.png.

4dca242 positions the shared AppShell .app-frame so auth, loading and notices paint above the mesh in DOM order. Added browser regression assertion and updated stacking comment. Node syntax and git diff --check pass; scripts/verify fast running. Stopped only my waiting Browser3 shell before any gate started; will requeue after fast. These eight partial plates are rejected as final evidence and will be recaptured. No other job processes changed.

Visual review of all eight fresh auth plates from Browser2 found the fixed mesh painting over auth heading, brand and fields, while positioned primitives remained visible. Real release-server probe confirmed the unpositioned wrapper (position:static), background z-index:0, and restored content with a positioning context. Diagnostic screenshots: /mnt/hdd/infraternal/artifacts/port-final/auth-stack-before.png and auth-stack-diagnostic.png. 4dca242 positions the shared AppShell .app-frame so auth, loading and notices paint above the mesh in DOM order. Added browser regression assertion and updated stacking comment. Node syntax and git diff --check pass; scripts/verify fast running. Stopped only my waiting Browser3 shell before any gate started; will requeue after fast. These eight partial plates are rejected as final evidence and will be recaptured. No other job processes changed.
Author
Owner

4dca242 full fast PASS exit0, all16 stages. 02d53b5 also applies docs/UI.md required Fraunces page-title typography to auth and makes signed-out auth share the available height with the fallback notice. Capture assertions cover positioned frame and Fraunces. Node syntax and diff whitespace pass. Final fast then Browser3 queued serially under load/gate rules.

Verbatim fast output:

WARN load5=9.44 exceeds online CPU count=8; timing-sensitive checks may be delayed
PASS fast: migrations are append-only (0.153s)
PASS fast: workspace package dependencies (0.217s)
PASS fast: JavaScript dependencies (0.006s)
PASS fast: build web app (8.326s)
PASS fast: cargo fmt --check (0.998s)
PASS fast: cargo clippy (20.047s)
PASS fast: cargo test (141.181s)
PASS fast: svelte-check (15.609s)
PASS fast: UI package svelte-check (7.826s)
PASS fast: stream package typecheck (9.757s)
PASS fast: Vitest (5.886s)
PASS fast: UI package Vitest (4.779s)
PASS fast: stream package Vitest (1.497s)
PASS fast: OpenAPI and TypeScript client drift (42.451s)
PASS fast: terminal TypeScript (2.746s)
PASS fast: terminal Vitest (3.689s)
4dca242 full fast PASS exit0, all16 stages. 02d53b5 also applies docs/UI.md required Fraunces page-title typography to auth and makes signed-out auth share the available height with the fallback notice. Capture assertions cover positioned frame and Fraunces. Node syntax and diff whitespace pass. Final fast then Browser3 queued serially under load/gate rules. Verbatim fast output: ```text WARN load5=9.44 exceeds online CPU count=8; timing-sensitive checks may be delayed PASS fast: migrations are append-only (0.153s) PASS fast: workspace package dependencies (0.217s) PASS fast: JavaScript dependencies (0.006s) PASS fast: build web app (8.326s) PASS fast: cargo fmt --check (0.998s) PASS fast: cargo clippy (20.047s) PASS fast: cargo test (141.181s) PASS fast: svelte-check (15.609s) PASS fast: UI package svelte-check (7.826s) PASS fast: stream package typecheck (9.757s) PASS fast: Vitest (5.886s) PASS fast: UI package Vitest (4.779s) PASS fast: stream package Vitest (1.497s) PASS fast: OpenAPI and TypeScript client drift (42.451s) PASS fast: terminal TypeScript (2.746s) PASS fast: terminal Vitest (3.689s) ```
Author
Owner

HEAD 02d53b5: scripts/verify fast PASS, all16 stages. Branch clean and committed. Browser3 remains queued in the same serial process (execsession49012) until load5<8 and no other heavy gate/release build. Full integration, browser lifecycle acceptance and final visual plates remain pending; merge gate is centrally orchestrated per latest owner policy.

Verbatim output:

WARN load5=10.07 exceeds online CPU count=8; timing-sensitive checks may be delayed
PASS fast: migrations are append-only (0.201s)
PASS fast: workspace package dependencies (0.287s)
PASS fast: JavaScript dependencies (0.006s)
PASS fast: build web app (8.698s)
PASS fast: cargo fmt --check (1.296s)
PASS fast: cargo clippy (16.949s)
PASS fast: cargo test (123.211s)
PASS fast: svelte-check (15.061s)
PASS fast: UI package svelte-check (5.050s)
PASS fast: stream package typecheck (6.061s)
PASS fast: Vitest (5.483s)
PASS fast: UI package Vitest (6.030s)
PASS fast: stream package Vitest (2.235s)
PASS fast: OpenAPI and TypeScript client drift (32.790s)
PASS fast: terminal TypeScript (4.224s)
PASS fast: terminal Vitest (1.938s)
HEAD 02d53b5: scripts/verify fast PASS, all16 stages. Branch clean and committed. Browser3 remains queued in the same serial process (execsession49012) until load5<8 and no other heavy gate/release build. Full integration, browser lifecycle acceptance and final visual plates remain pending; merge gate is centrally orchestrated per latest owner policy. Verbatim output: ```text WARN load5=10.07 exceeds online CPU count=8; timing-sensitive checks may be delayed PASS fast: migrations are append-only (0.201s) PASS fast: workspace package dependencies (0.287s) PASS fast: JavaScript dependencies (0.006s) PASS fast: build web app (8.698s) PASS fast: cargo fmt --check (1.296s) PASS fast: cargo clippy (16.949s) PASS fast: cargo test (123.211s) PASS fast: svelte-check (15.061s) PASS fast: UI package svelte-check (5.050s) PASS fast: stream package typecheck (6.061s) PASS fast: Vitest (5.483s) PASS fast: UI package Vitest (6.030s) PASS fast: stream package Vitest (2.235s) PASS fast: OpenAPI and TypeScript client drift (32.790s) PASS fast: terminal TypeScript (4.224s) PASS fast: terminal Vitest (1.938s) ```
Author
Owner

After finalfast02d53b5 all16PASS, its waiting serialqueue exec49012 exited143 before Browser3 started (no /tmp/port-final-sol-browser-3.log). Cause not established; I did not signal that process. Confirmed no Browser3 process remained, then requeued with the original load5<8/noheavy/nootherrelease checks, polling120s. Commits/fast output intact. Please keep this job’s explicitly authorized integration/browser/visual work running unless the owner changes scope.

After finalfast02d53b5 all16PASS, its waiting serialqueue exec49012 exited143 before Browser3 started (no /tmp/port-final-sol-browser-3.log). Cause not established; I did not signal that process. Confirmed no Browser3 process remained, then requeued with the original load5<8/noheavy/nootherrelease checks, polling120s. Commits/fast output intact. Please keep this job’s explicitly authorized integration/browser/visual work running unless the owner changes scope.
Author
Owner

Further auth material review: the old opaque auth/loading page background would hide the shared theme mesh once the stacking fix restored the page. 1c112c5 removes that backdrop; the shared mesh remains the page material and the existing calternal Card remains the form surface. Added capture assertion for transparent page background. Node syntax/diff whitespace PASS. Fullfastmesh then Browser3 queued serially (exec39009), /tmp/port-final-sol-fast-auth-mesh.log -> /tmp/port-final-sol-browser-3.log. Only my own waiting queue was stopped before its Browser3 start.

Further auth material review: the old opaque auth/loading page background would hide the shared theme mesh once the stacking fix restored the page. 1c112c5 removes that backdrop; the shared mesh remains the page material and the existing calternal Card remains the form surface. Added capture assertion for transparent page background. Node syntax/diff whitespace PASS. Fullfastmesh then Browser3 queued serially (exec39009), /tmp/port-final-sol-fast-auth-mesh.log -> /tmp/port-final-sol-browser-3.log. Only my own waiting queue was stopped before its Browser3 start.
Author
Owner

1c112c5 fast attempt failed the existing process-wide allocation test:141 allocations vs <100. Source explicitly accounts for other tests running in parallel; SAME workspace test binary run with --exact isolates this test and PASSes exit0. A separate cargo targeted invocation also PASSes. Production framing and allocation assertion unchanged. Fullfast rerun then Browser3 queued serially (exec58944); currentload1>10 preventsstart.

Verbatim failed gate:

WARN load5=8.75 exceeds online CPU count=8; timing-sensitive checks may be delayed
PASS fast: migrations are append-only (0.121s)
PASS fast: workspace package dependencies (0.197s)
PASS fast: JavaScript dependencies (0.004s)
PASS fast: build web app (6.762s)
PASS fast: cargo fmt --check (1.068s)
PASS fast: cargo clippy (14.516s)
FAIL fast: cargo test (57.750s)
   Compiling infraternal-server v0.0.1 (/home/kayg/wt/calternal-port/crates/server)
   Compiling infraternal v0.0.1 (/home/kayg/wt/calternal-port/crates/infraternal)
    Finished `test` profile [unoptimized] target(s) in 55.83s
     Running unittests src/main.rs (target/debug/deps/infraternal-786ee3abac3a281d)

running 41 tests
test cli::tests::log_snapshot_deadline_defaults_to_five_seconds_and_follow_is_unbounded ... ok
test http::tests::caller_idempotency_keys_are_ulids ... ok
test cli::tests::log_timeout_override_is_bounded_and_liveness_errors_have_a_stable_exit_code ... ok
test http::tests::client_error_exit_codes_follow_the_contract_registry ... ok
test http::tests::addresses_and_plan_ids_use_proto_validation ... ok
test http::tests::plan_errors_explain_the_next_safe_step ... ok
test login::tests::fallback_rejects_hard_linked_files ... ok
test login::tests::fallback_creates_and_replaces_only_private_regular_files ... ok
test login::tests::credential_slots_are_isolated_and_validate_binding ... ok
test login::tests::fallback_rejects_symlinks_and_permissive_files ... ok
test login::tests::keychain_record_rejects_swapped_binding ... ok
test login::tests::keychain_success_surfaces_fallback_cleanup_failure_and_blocks_stale_reads ... ok
test login::tests::refresh_process_child ... ok
test login::tests::source_has_no_direct_secret_output ... ok
test login::tests::server_url_transport_policy_accepts_only_safe_origins ... ok
test login::tests::verification_uri_must_match_the_normalized_server_origin ... ok
test login::tests::keychain_and_fallback_transitions_never_replay_old_material ... ok
test mcp::tests::container_logs_defaults_are_bounded ... ok
test http::tests::expired_access_tokens_refresh_before_the_request ... ok
test login::tests::authentication_client_never_forwards_post_bodies_across_redirects ... ok
test mcp::tests::list_input_is_an_optional_filter_object ... ok
test mcp::tests::tool_input_defaults_are_safe_for_destructive_calls ... ok
test http::tests::server_url_rejects_embedded_credentials_and_query_data ... ok
test mcp::tests::host_trust_tool_defaults_to_no_replacement_and_no_mutation ... ok
test mcp::tests::every_tool_publishes_output_schema_and_behavior_annotations ... ok
test login::tests::unreachable_server_keeps_the_local_fallback_for_retry ... ok
test stream::tests::invalid_channel_state_closes_websocket_with_protocol_code_1002 ... ok
test mcp::tests::container_logs_has_a_complete_output_schema ... ok
test stream::tests::malformed_frame_closes_websocket_with_protocol_code_1002 ... ok
test mcp::tests::tool_router_contains_the_contract_tool_names ... ok
test stream::tests::malformed_log_record_closes_channel_with_invalid_request ... ok
test tests::backup_command_parses_explicit_source_and_destination ... ok
test tests::mcp_setup_and_login_parse_with_global_server ... ok
test tests::server_defaults_match_the_public_local_origin ... ok
test stream::tests::oversized_frame_closes_websocket_with_message_too_big_code_1009 ... ok
test tests::accepted_server_socket_has_tcp_nodelay_and_handler_gets_real_peer ... ok
test stream::tests::oversized_log_record_closes_channel_with_record_too_large ... ok
test http::tests::resource_client_does_not_follow_bearer_or_body_redirects ... ok
test stream::tests::silent_server_gets_ping_then_liveness_close_4008 ... ok
test login::tests::independent_cli_and_mcp_processes_rotate_once_and_reuse_saved_access ... ok
test ssh::tests::detach_bounds_a_stalled_close_send ... ok

test result: ok. 41 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.29s

     Running tests/agent_tunnel.rs (target/debug/deps/agent_tunnel-3131a6e194ddc3c7)

running 1 test
test real_infraternal_agent_process_enrolls_and_reconnects_with_new_nonce ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.94s

     Running tests/cli_mcp.rs (target/debug/deps/cli_mcp-9ef0f03cb3b9746f)

running 1 test
test cli_and_mcp_use_the_public_http_contract ... ignored, requires the compiled server, rootful Docker and rootless Podman

test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running tests/server_startup.rs (target/debug/deps/server_startup-49c168fdcb7ec4e6)

running 1 test
test setup_banner_uses_stdout_and_database_uses_the_data_directory ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.51s

     Running tests/sshd_test_support.rs (target/debug/deps/sshd_test_support-88277c84aa135daf)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running unittests src/lib.rs (target/debug/deps/infraternal_agent-eb93cfc1582874a3)

running 15 tests
test remote::tests::benchmark_tunnel_credit_accounting ... ignored, benchmark only on the perf-test VM
test remote::tests::enrollment_origin_only_allows_loopback_http_or_https_root ... ok
test remote::tests::physical_tunnel_credit_is_shared_across_clients_and_released ... ok
test remote::tests::private_identity_files_are_owner_only_and_not_overwritten ... ok
test tests::failed_commit_cancels_persistent_exec_before_or_after_reservation ... ok
test private_signer_tests::signer_reopen_tightens_before_read_and_refuses_substituted_files ... ok
test tests::finite_snapshot_excludes_records_after_the_open_timestamp ... ok
test tests::persistent_exec_first_attach_replays_the_real_shell_prompt ... ignored, requires rootful Docker and rootless Podman
test tests::persistent_exec_termination_preempts_a_full_outbound_send ... ignored, requires real Docker
test tests::real_engine_following_log_stream_is_bounded_for_a_finite_snapshot ... ignored, requires rootful Docker and rootless Podman
test tests::real_engines_batch_log_records_under_a_10k_lines_per_second_flood ... ignored, requires rootful Docker and rootless Podman
test tests::stalled_nonpersistent_pty_input_does_not_hold_cleanup ... ignored, requires real Docker and rootless Podman
test tests::persistent_exec_registry_deduplicates_open_keys_and_enforces_user_limit ... ok
test tests::in_process_transport_uses_frames_and_reports_unavailable_stats ... ok
test tests::grants_reject_tamper_wrong_tunnel_and_replay ... ok

test result: ok. 9 passed; 0 failed; 6 ignored; 0 measured; 0 filtered out; finished in 0.06s

     Running unittests src/lib.rs (target/debug/deps/infraternal_engine-d83a36322f037e5d)

running 20 tests
test cleanup_tests::cancelled_close_aborts_producer_before_cleanup_can_be_cancelled ... ignored, run explicitly; the global allocator regression test must not run beside this probe
test bollard_adapter::tests::rootless_socket_candidates_use_proc_uid_without_exported_environment ... ok
test bollard_adapter::tests::raw_podman_responses_preserve_stopped_health_and_pod_identity ... ok
test cleanup_tests::captured_exec_zombie_state_is_bound_to_the_original_pid_start_time ... ok
test cleanup_tests::missing_host_proc_is_unknown_not_a_dead_original_group ... ok
test error::tests::maps_http_registry_codes_and_engine_details ... ok
test cleanup_tests::host_marker_scan_detects_survivors_and_reports_incomplete_inspection ... ok
test cleanup_tests::host_marker_scan_ignores_zombies_but_rejects_live_unreadable_processes ... ok
test logs::tests::emits_a_final_line_without_a_newline ... ok
test logs::tests::eof_flushes_partial_streams_in_arrival_order ... ok
test logs::tests::leaves_line_bytes_unchanged_when_timestamps_are_disabled ... ok
test cleanup_tests::process_namespace_is_retained_when_process_group_cannot_be_signaled ... ok
test logs::tests::eof_flushes_partial_streams_in_reverse_arrival_order ... ok
test logs::tests::keeps_streams_and_parses_engine_timestamps ... ok
test error::tests::mutation_transport_failures_have_unknown_outcomes ... ok
test cleanup_tests::host_marker_scan_skips_only_inaccessible_processes_outside_target_namespace ... ok
test cleanup_tests::host_marker_scan_signals_only_the_marked_pid_through_pidfd ... ok
test logs::tests::splits_lines_across_chunks_and_marks_long_lines ... ok
test logs::tests::steady_state_framing_does_not_allocate_per_chunk ... FAILED
test cleanup_tests::timed_out_cleanup_reports_unknown_but_retains_its_slot_until_exit ... ok

failures:

---- logs::tests::steady_state_framing_does_not_allocate_per_chunk stdout ----

thread 'logs::tests::steady_state_framing_does_not_allocate_per_chunk' (2139364) panicked at crates/engine/src/logs.rs:349:9:
log framing allocated per chunk after warmup: Stats { allocations: 141, deallocations: 220, reallocations: 51, bytes_allocated: 29488, bytes_deallocated: 16370, bytes_reallocated: 8260 }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    logs::tests::steady_state_framing_does_not_allocate_per_chunk

test result: FAILED. 18 passed; 1 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.01s

error: test failed, to rerun pass `-p infraternal-engine --lib`

Verbatim SAME workspace binary isolated test:


running 1 test
test logs::tests::steady_state_framing_does_not_allocate_per_chunk ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 19 filtered out; finished in 0.00s

1c112c5 fast attempt failed the existing process-wide allocation test:141 allocations vs <100. Source explicitly accounts for other tests running in parallel; SAME workspace test binary run with --exact isolates this test and PASSes exit0. A separate cargo targeted invocation also PASSes. Production framing and allocation assertion unchanged. Fullfast rerun then Browser3 queued serially (exec58944); currentload1>10 preventsstart. Verbatim failed gate: ```text WARN load5=8.75 exceeds online CPU count=8; timing-sensitive checks may be delayed PASS fast: migrations are append-only (0.121s) PASS fast: workspace package dependencies (0.197s) PASS fast: JavaScript dependencies (0.004s) PASS fast: build web app (6.762s) PASS fast: cargo fmt --check (1.068s) PASS fast: cargo clippy (14.516s) FAIL fast: cargo test (57.750s) Compiling infraternal-server v0.0.1 (/home/kayg/wt/calternal-port/crates/server) Compiling infraternal v0.0.1 (/home/kayg/wt/calternal-port/crates/infraternal) Finished `test` profile [unoptimized] target(s) in 55.83s Running unittests src/main.rs (target/debug/deps/infraternal-786ee3abac3a281d) running 41 tests test cli::tests::log_snapshot_deadline_defaults_to_five_seconds_and_follow_is_unbounded ... ok test http::tests::caller_idempotency_keys_are_ulids ... ok test cli::tests::log_timeout_override_is_bounded_and_liveness_errors_have_a_stable_exit_code ... ok test http::tests::client_error_exit_codes_follow_the_contract_registry ... ok test http::tests::addresses_and_plan_ids_use_proto_validation ... ok test http::tests::plan_errors_explain_the_next_safe_step ... ok test login::tests::fallback_rejects_hard_linked_files ... ok test login::tests::fallback_creates_and_replaces_only_private_regular_files ... ok test login::tests::credential_slots_are_isolated_and_validate_binding ... ok test login::tests::fallback_rejects_symlinks_and_permissive_files ... ok test login::tests::keychain_record_rejects_swapped_binding ... ok test login::tests::keychain_success_surfaces_fallback_cleanup_failure_and_blocks_stale_reads ... ok test login::tests::refresh_process_child ... ok test login::tests::source_has_no_direct_secret_output ... ok test login::tests::server_url_transport_policy_accepts_only_safe_origins ... ok test login::tests::verification_uri_must_match_the_normalized_server_origin ... ok test login::tests::keychain_and_fallback_transitions_never_replay_old_material ... ok test mcp::tests::container_logs_defaults_are_bounded ... ok test http::tests::expired_access_tokens_refresh_before_the_request ... ok test login::tests::authentication_client_never_forwards_post_bodies_across_redirects ... ok test mcp::tests::list_input_is_an_optional_filter_object ... ok test mcp::tests::tool_input_defaults_are_safe_for_destructive_calls ... ok test http::tests::server_url_rejects_embedded_credentials_and_query_data ... ok test mcp::tests::host_trust_tool_defaults_to_no_replacement_and_no_mutation ... ok test mcp::tests::every_tool_publishes_output_schema_and_behavior_annotations ... ok test login::tests::unreachable_server_keeps_the_local_fallback_for_retry ... ok test stream::tests::invalid_channel_state_closes_websocket_with_protocol_code_1002 ... ok test mcp::tests::container_logs_has_a_complete_output_schema ... ok test stream::tests::malformed_frame_closes_websocket_with_protocol_code_1002 ... ok test mcp::tests::tool_router_contains_the_contract_tool_names ... ok test stream::tests::malformed_log_record_closes_channel_with_invalid_request ... ok test tests::backup_command_parses_explicit_source_and_destination ... ok test tests::mcp_setup_and_login_parse_with_global_server ... ok test tests::server_defaults_match_the_public_local_origin ... ok test stream::tests::oversized_frame_closes_websocket_with_message_too_big_code_1009 ... ok test tests::accepted_server_socket_has_tcp_nodelay_and_handler_gets_real_peer ... ok test stream::tests::oversized_log_record_closes_channel_with_record_too_large ... ok test http::tests::resource_client_does_not_follow_bearer_or_body_redirects ... ok test stream::tests::silent_server_gets_ping_then_liveness_close_4008 ... ok test login::tests::independent_cli_and_mcp_processes_rotate_once_and_reuse_saved_access ... ok test ssh::tests::detach_bounds_a_stalled_close_send ... ok test result: ok. 41 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.29s Running tests/agent_tunnel.rs (target/debug/deps/agent_tunnel-3131a6e194ddc3c7) running 1 test test real_infraternal_agent_process_enrolls_and_reconnects_with_new_nonce ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.94s Running tests/cli_mcp.rs (target/debug/deps/cli_mcp-9ef0f03cb3b9746f) running 1 test test cli_and_mcp_use_the_public_http_contract ... ignored, requires the compiled server, rootful Docker and rootless Podman test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s Running tests/server_startup.rs (target/debug/deps/server_startup-49c168fdcb7ec4e6) running 1 test test setup_banner_uses_stdout_and_database_uses_the_data_directory ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.51s Running tests/sshd_test_support.rs (target/debug/deps/sshd_test_support-88277c84aa135daf) running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s Running unittests src/lib.rs (target/debug/deps/infraternal_agent-eb93cfc1582874a3) running 15 tests test remote::tests::benchmark_tunnel_credit_accounting ... ignored, benchmark only on the perf-test VM test remote::tests::enrollment_origin_only_allows_loopback_http_or_https_root ... ok test remote::tests::physical_tunnel_credit_is_shared_across_clients_and_released ... ok test remote::tests::private_identity_files_are_owner_only_and_not_overwritten ... ok test tests::failed_commit_cancels_persistent_exec_before_or_after_reservation ... ok test private_signer_tests::signer_reopen_tightens_before_read_and_refuses_substituted_files ... ok test tests::finite_snapshot_excludes_records_after_the_open_timestamp ... ok test tests::persistent_exec_first_attach_replays_the_real_shell_prompt ... ignored, requires rootful Docker and rootless Podman test tests::persistent_exec_termination_preempts_a_full_outbound_send ... ignored, requires real Docker test tests::real_engine_following_log_stream_is_bounded_for_a_finite_snapshot ... ignored, requires rootful Docker and rootless Podman test tests::real_engines_batch_log_records_under_a_10k_lines_per_second_flood ... ignored, requires rootful Docker and rootless Podman test tests::stalled_nonpersistent_pty_input_does_not_hold_cleanup ... ignored, requires real Docker and rootless Podman test tests::persistent_exec_registry_deduplicates_open_keys_and_enforces_user_limit ... ok test tests::in_process_transport_uses_frames_and_reports_unavailable_stats ... ok test tests::grants_reject_tamper_wrong_tunnel_and_replay ... ok test result: ok. 9 passed; 0 failed; 6 ignored; 0 measured; 0 filtered out; finished in 0.06s Running unittests src/lib.rs (target/debug/deps/infraternal_engine-d83a36322f037e5d) running 20 tests test cleanup_tests::cancelled_close_aborts_producer_before_cleanup_can_be_cancelled ... ignored, run explicitly; the global allocator regression test must not run beside this probe test bollard_adapter::tests::rootless_socket_candidates_use_proc_uid_without_exported_environment ... ok test bollard_adapter::tests::raw_podman_responses_preserve_stopped_health_and_pod_identity ... ok test cleanup_tests::captured_exec_zombie_state_is_bound_to_the_original_pid_start_time ... ok test cleanup_tests::missing_host_proc_is_unknown_not_a_dead_original_group ... ok test error::tests::maps_http_registry_codes_and_engine_details ... ok test cleanup_tests::host_marker_scan_detects_survivors_and_reports_incomplete_inspection ... ok test cleanup_tests::host_marker_scan_ignores_zombies_but_rejects_live_unreadable_processes ... ok test logs::tests::emits_a_final_line_without_a_newline ... ok test logs::tests::eof_flushes_partial_streams_in_arrival_order ... ok test logs::tests::leaves_line_bytes_unchanged_when_timestamps_are_disabled ... ok test cleanup_tests::process_namespace_is_retained_when_process_group_cannot_be_signaled ... ok test logs::tests::eof_flushes_partial_streams_in_reverse_arrival_order ... ok test logs::tests::keeps_streams_and_parses_engine_timestamps ... ok test error::tests::mutation_transport_failures_have_unknown_outcomes ... ok test cleanup_tests::host_marker_scan_skips_only_inaccessible_processes_outside_target_namespace ... ok test cleanup_tests::host_marker_scan_signals_only_the_marked_pid_through_pidfd ... ok test logs::tests::splits_lines_across_chunks_and_marks_long_lines ... ok test logs::tests::steady_state_framing_does_not_allocate_per_chunk ... FAILED test cleanup_tests::timed_out_cleanup_reports_unknown_but_retains_its_slot_until_exit ... ok failures: ---- logs::tests::steady_state_framing_does_not_allocate_per_chunk stdout ---- thread 'logs::tests::steady_state_framing_does_not_allocate_per_chunk' (2139364) panicked at crates/engine/src/logs.rs:349:9: log framing allocated per chunk after warmup: Stats { allocations: 141, deallocations: 220, reallocations: 51, bytes_allocated: 29488, bytes_deallocated: 16370, bytes_reallocated: 8260 } note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: logs::tests::steady_state_framing_does_not_allocate_per_chunk test result: FAILED. 18 passed; 1 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.01s error: test failed, to rerun pass `-p infraternal-engine --lib` ``` Verbatim SAME workspace binary isolated test: ```text running 1 test test logs::tests::steady_state_framing_does_not_allocate_per_chunk ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 19 filtered out; finished in 0.00s ```
Author
Owner

port-final continuation (Claude Opus 5.5), branch calternal-port, head fb28161. Not pushed; merge gate is still pending (orchestrator).

Integration. Merged origin/dev 6131a8b (provider runtime, #49) into 346486c. Conflicts: DECISIONS.md keeps dev's §24/§25 and renumbers the design-system amendment and working-features rule to §26/§27. private_storage.rs takes dev's version. Generated files: the OpenAPI/TS drift check passes.

Lane D. git grep -i 'shadcn|bits-ui|tailwind-variants|tw-animate|tailwind-merge|\bcn(' now matches only historical text in DECISIONS.md, docs/research/calternal-port.md and docs/research/front-end.md. bun.lock has no matches.

Gates

fast  @346486c  sub-portfinal: 16/16 PASS
fast  @fb28161  sub-portfinal: 16/16 PASS
browser @346486c sub-portfinal-b (the single allowed run): FAIL in "Playwright against release server"
  (harness: UUID Idempotency-Key on /auth/refresh -> 422; the contract requires a ULID)

After that run, only the Playwright step was rerun, against my own release builds of each head. It was serialized behind merge, browser and integration runs. Artifacts: /mnt/hdd/infraternal/artifacts/port-final/sub-portfinal-b2. Each run found the next real defect:

  • a28a633: harness sends a ULID key; the single-tab fallback (locks-only and neither) now PASSes.
  • 7f1ca0e: "Jump to latest" flake, root-caused. TanStack Virtual's re-measure scroll events turned follow mode back off. Now only user intent pauses following. PASS.
  • 0913a23 + e0bdbaf: a back/forward-cached document never reports its WebSocket close to Playwright or CDP. The pagehide, 50-transition, 20-reload and one-terminal checks now count live stream connections on the server, from a new "stream connection closed" log line. This proved that pagehide really closes the socket.
  • 428bad9: product bug. The page was never restored from the BFCache; notRestoredReasons was broadcastchannel-message, because the session BroadcastChannel stayed open while the page was cached. The channel now closes on pagehide; on a persisted pageshow it rejoins and revalidates the credential. Result: ACCEPT stream lifecycle: BFCache restored the mounted log view; SPA transitions=50, reloads=20, log opens=23, active client sockets=0, old-document sockets=0, post-close log DATA delta=0.
  • 2ea69e3 / 134707b: harness fixes. Text under the collapsed calternal header band is frosted by design, so it no longer counts as overlap. Logs open on demand, so the check opens the log viewer before expecting a stream after re-sign-in.
  • b63499d: product bug. A reloaded terminal pane resumed from the old document's consumed cursor, so its fresh emulator showed only output after that cursor. A pane now omits resume_from until its own emulator has rendered output, so the retained buffer is replayed (contracts §3.11). Transport recovery and BFCache still resume from the cursor. The workspace reload check now PASSes.
  • ca92c95: long workspace tab names overflowed a 390px screen (745px wide). They are now capped and truncated.
  • fb28161: product bug. The active pane re-focused the terminal on every DATA frame, stealing keyboard focus.
  • Still failing: keyboard "Close pane 2" in checkTerminalWorkspace. Focus is on the button before Enter, then lands in the split pane's terminal host after the capture's theme and viewport change. The likely source is a ghostty-web refocus on re-theme or resize. Not fixed. The steps after it in the browser check have not run yet.

Visual fixes against calternal-ref:

  • The Settings rail is now calternal's FloatingSidebar (icons, measured capsule), shared by Profile and Appearance (046a3ee, e6e0c0d).
  • The containers "Filters" disclosure no longer renders full-width on desktop (46f78a4).
  • Log timestamps use the caption size; --danger-soft is now defined (769a304).
  • Ported tokens from calternal-app.css that were missing (0113468): --type-label/caption/eyebrow/..., --ui-heading-*, --pill-*, --feed-toolbar-*, --scrim-tint-palette, and the two-band --focus-ring-outer/inner. Before this, every Pill label fell back to body size, and 31 outline: var(--focus-ring) rules were invalid. The ring is now calternal's outline ring.

Plates (calternal on the left): /mnt/hdd/infraternal/artifacts/port-final/sub-portfinal-b2-plates/index.html (52 plates).

Remaining

  1. Fix the focus-steal in the keyboard close-pane check, then finish the rest of the browser check. The full browser and integration gates still need to pass on the final head.
  2. Mobile log rows keep a 10rem timestamp column, so the text truncates early at 390px; the timestamp should stack above the text.
  3. A long title truncates heavily on mobile next to three header islands (Terminals, AI agent tokens).
  4. One-off: /terminals networkidle timed out once at 428bad9 run 1 and did not reproduce in the next run.
  5. Audit items F2–F10 and recopy.patch (with the light-glass alpha override) are deliberately not applied.
port-final continuation (Claude Opus 5.5), branch `calternal-port`, head **`fb28161`**. Not pushed; merge gate is still pending (orchestrator). **Integration.** Merged `origin/dev` `6131a8b` (provider runtime, #49) into `346486c`. Conflicts: DECISIONS.md keeps dev's §24/§25 and renumbers the design-system amendment and working-features rule to §26/§27. `private_storage.rs` takes dev's version. Generated files: the OpenAPI/TS drift check passes. **Lane D.** `git grep -i 'shadcn|bits-ui|tailwind-variants|tw-animate|tailwind-merge|\bcn('` now matches only historical text in DECISIONS.md, docs/research/calternal-port.md and docs/research/front-end.md. `bun.lock` has no matches. **Gates** ```text fast @346486c sub-portfinal: 16/16 PASS fast @fb28161 sub-portfinal: 16/16 PASS browser @346486c sub-portfinal-b (the single allowed run): FAIL in "Playwright against release server" (harness: UUID Idempotency-Key on /auth/refresh -> 422; the contract requires a ULID) ``` After that run, only the Playwright step was rerun, against my own release builds of each head. It was serialized behind merge, browser and integration runs. Artifacts: `/mnt/hdd/infraternal/artifacts/port-final/sub-portfinal-b2`. Each run found the next real defect: - `a28a633`: harness sends a ULID key; the single-tab fallback (locks-only and neither) now PASSes. - `7f1ca0e`: "Jump to latest" flake, root-caused. TanStack Virtual's re-measure scroll events turned follow mode back off. Now only user intent pauses following. PASS. - `0913a23` + `e0bdbaf`: a back/forward-cached document never reports its WebSocket close to Playwright or CDP. The pagehide, 50-transition, 20-reload and one-terminal checks now count live stream connections on the server, from a new "stream connection closed" log line. This proved that pagehide really closes the socket. - `428bad9`: **product bug.** The page was never restored from the BFCache; `notRestoredReasons` was `broadcastchannel-message`, because the session BroadcastChannel stayed open while the page was cached. The channel now closes on pagehide; on a persisted pageshow it rejoins and revalidates the credential. Result: **ACCEPT stream lifecycle: BFCache restored the mounted log view; SPA transitions=50, reloads=20, log opens=23, active client sockets=0, old-document sockets=0, post-close log DATA delta=0.** - `2ea69e3` / `134707b`: harness fixes. Text under the collapsed calternal header band is frosted by design, so it no longer counts as overlap. Logs open on demand, so the check opens the log viewer before expecting a stream after re-sign-in. - `b63499d`: **product bug.** A reloaded terminal pane resumed from the old document's consumed cursor, so its fresh emulator showed only output after that cursor. A pane now omits `resume_from` until its own emulator has rendered output, so the retained buffer is replayed (contracts §3.11). Transport recovery and BFCache still resume from the cursor. The workspace reload check now PASSes. - `ca92c95`: long workspace tab names overflowed a 390px screen (745px wide). They are now capped and truncated. - `fb28161`: **product bug.** The active pane re-focused the terminal on every DATA frame, stealing keyboard focus. - **Still failing:** keyboard "Close pane 2" in `checkTerminalWorkspace`. Focus is on the button before Enter, then lands in the split pane's terminal host after the capture's theme and viewport change. The likely source is a ghostty-web refocus on re-theme or resize. Not fixed. The steps after it in the browser check have not run yet. **Visual fixes against calternal-ref:** - The Settings rail is now calternal's `FloatingSidebar` (icons, measured capsule), shared by Profile and Appearance (`046a3ee`, `e6e0c0d`). - The containers "Filters" disclosure no longer renders full-width on desktop (`46f78a4`). - Log timestamps use the caption size; `--danger-soft` is now defined (`769a304`). - **Ported tokens from calternal-app.css that were missing** (`0113468`): `--type-label/caption/eyebrow/...`, `--ui-heading-*`, `--pill-*`, `--feed-toolbar-*`, `--scrim-tint-palette`, and the two-band `--focus-ring-outer/inner`. Before this, every Pill label fell back to body size, and 31 `outline: var(--focus-ring)` rules were invalid. The ring is now calternal's outline ring. Plates (calternal on the left): `/mnt/hdd/infraternal/artifacts/port-final/sub-portfinal-b2-plates/index.html` (52 plates). **Remaining** 1. Fix the focus-steal in the keyboard close-pane check, then finish the rest of the browser check. The full browser and integration gates still need to pass on the final head. 2. Mobile log rows keep a 10rem timestamp column, so the text truncates early at 390px; the timestamp should stack above the text. 3. A long title truncates heavily on mobile next to three header islands (Terminals, AI agent tokens). 4. One-off: `/terminals` networkidle timed out once at 428bad9 run 1 and did not reproduce in the next run. 5. Audit items F2–F10 and recopy.patch (with the light-glass alpha override) are deliberately not applied.
Author
Owner

Starting defensive read-only review-port-auth at detached HEAD 38ddd3da75 on calternal-port history. Scope: 6fd2932 and 428bad9, restored-page credentials, multi-tab rotation/sign-out, stream tickets and API client. No source edits, commits or Rust builds. Findings: /mnt/hdd/infraternal/jobs/review-port-auth/findings.md.

Starting defensive read-only review-port-auth at detached HEAD 38ddd3da756de99a25381e0491f68b64fb277ce7 on calternal-port history. Scope: 6fd2932 and 428bad9, restored-page credentials, multi-tab rotation/sign-out, stream tickets and API client. No source edits, commits or Rust builds. Findings: /mnt/hdd/infraternal/jobs/review-port-auth/findings.md.
Author
Owner

review-port-auth

HEAD: 38ddd3da75 (detached; calternal-port history). Read-only review of 6fd2932 and 428bad9 plus surrounding auth/API/stream code. No source edits or commits.

Verdict: do not merge.

  • Major / P1 — packages/web/src/lib/auth.svelte.ts:104 (also :302, :317): a cached tab misses sign-out and adopts a later sign-in from another tab, violating the local-passkey-only re-entry contract; persist a nonsecret monotonic sign-out epoch, check it before restore/peer adoption/refresh, and bind session messages and refresh work to that epoch.
  • Major / P1 — packages/web/src/lib/auth.svelte.ts:200 (also :209, :146): sign-out during the 250 ms peer wait wakes the waiter but falls through to a new refresh using the post-sign-out epoch, allowing a successful response to restore the session; recheck the original epoch after every await and pass that epoch into performRefresh instead of recapturing it.
  • Follow-up / P2 — packages/web/src/lib/api.ts:27 (also auth.svelte.ts:104 and stream-attachment.svelte.ts:86): ordinary API calls bypass the restored-page barrier and can send the old access credential during peer handoff; gate authenticated API dispatch on restore reconciliation and acquire the current credential afterward, keeping reconciliation's own requests exempt to avoid recursion.

Evidence so far

External local failure injection compiles the unchanged auth and API source using the installed Svelte compiler, then drives pagehide/pageshow, peer replies and fetch results. No real credentials or server requests. nice -n 15 bun /mnt/hdd/infraternal/jobs/review-port-auth/check.mjs confirms both P1 defects and the P2 gap; it also confirms normal rotation handoff avoids old-token requests and completed server sign-out eventually clears the restored tab. This is diagnostic evidence, not a production-browser or merge gate. Additional scenario checks pending.

The missed-signout regression is enabled by closing the channel in 428bad9; 6fd2932's peer-first restore adopts the later sign-in directly. The peer-wait cancellation defect already exists in surrounding refresh code and is exercised by 6fd2932's restore path. Neither finding claims that the server accepts a revoked credential.

# review-port-auth HEAD: 38ddd3da756de99a25381e0491f68b64fb277ce7 (detached; calternal-port history). Read-only review of 6fd2932 and 428bad9 plus surrounding auth/API/stream code. No source edits or commits. Verdict: **do not merge**. - **Major / P1** — `packages/web/src/lib/auth.svelte.ts:104` (also :302, :317): a cached tab misses sign-out and adopts a later sign-in from another tab, violating the local-passkey-only re-entry contract; persist a nonsecret monotonic sign-out epoch, check it before restore/peer adoption/refresh, and bind session messages and refresh work to that epoch. - **Major / P1** — `packages/web/src/lib/auth.svelte.ts:200` (also :209, :146): sign-out during the 250 ms peer wait wakes the waiter but falls through to a new refresh using the post-sign-out epoch, allowing a successful response to restore the session; recheck the original epoch after every await and pass that epoch into performRefresh instead of recapturing it. - **Follow-up / P2** — `packages/web/src/lib/api.ts:27` (also auth.svelte.ts:104 and stream-attachment.svelte.ts:86): ordinary API calls bypass the restored-page barrier and can send the old access credential during peer handoff; gate authenticated API dispatch on restore reconciliation and acquire the current credential afterward, keeping reconciliation's own requests exempt to avoid recursion. ## Evidence so far External local failure injection compiles the unchanged auth and API source using the installed Svelte compiler, then drives pagehide/pageshow, peer replies and fetch results. No real credentials or server requests. `nice -n 15 bun /mnt/hdd/infraternal/jobs/review-port-auth/check.mjs` confirms both P1 defects and the P2 gap; it also confirms normal rotation handoff avoids old-token requests and completed server sign-out eventually clears the restored tab. This is diagnostic evidence, not a production-browser or merge gate. Additional scenario checks pending. The missed-signout regression is enabled by closing the channel in 428bad9; 6fd2932's peer-first restore adopts the later sign-in directly. The peer-wait cancellation defect already exists in surrounding refresh code and is exercised by 6fd2932's restore path. Neither finding claims that the server accepts a revoked credential.
Author
Owner

Finished read-only review at unchanged HEAD 38ddd3da75. Verdict: do not merge. No commits or source changes.

review-port-auth

HEAD: 38ddd3da75 (detached; calternal-port history). Read-only review of 6fd2932 and 428bad9 plus surrounding auth/API/stream code. No source edits or commits.

Verdict: do not merge.

  • Major / P1 — packages/web/src/lib/auth.svelte.ts:104 (also :302, :317): a cached tab misses sign-out and adopts a later sign-in from another tab, violating the local-passkey-only re-entry contract; persist a nonsecret monotonic sign-out epoch, check it before restore/peer adoption/refresh, and bind session messages and refresh work to that epoch.
  • Major / P1 — packages/web/src/lib/auth.svelte.ts:200 (also :209, :146): sign-out during the 250 ms peer wait wakes the waiter but falls through to a new refresh using the post-sign-out epoch, allowing a successful response to restore the session; recheck the original epoch after every await and pass that epoch into performRefresh instead of recapturing it.
  • Follow-up / P2 — packages/web/src/lib/api.ts:27 (also auth.svelte.ts:104 and stream-attachment.svelte.ts:86): ordinary API calls bypass the restored-page barrier and can send the old access credential during peer handoff; gate authenticated API dispatch on restore reconciliation and acquire the current credential afterward, keeping reconciliation's own requests exempt to avoid recursion.

Concrete scenarios and impact

  1. Refresh rotated in another tab while cached: pagehide closes the channel; storage advances; persisted pageshow asks a live peer under the refresh lock. With a current peer reply, the restored tab adopts the newer credential, sends no held-token /account request, and does not rotate the cookie. The fixture confirms this. Stream resume waits on afterPageShowRevalidation; auth's listener is registered before stream's listener through its static import. Ordinary inventory/API dispatch has no such barrier (P2 above).
  2. Sign-out while cached, no later login: no sign-out epoch or tombstone is stored. The restored tab first sends its held credential to /account because sign-out does not advance the stored session generation. With completed server revocation, /account and refresh return 401 and the tab clears. This uses a revoked credential on the wire but does not bypass server authorization. If another tab completes a later sign-in before restore, the frozen tab instead adopts the new credential (or refreshes the new cookie after peer timeout), without a local ceremony: P1 above. This also permits an account change in a previously authenticated document.
  3. Sign-out during peer wait: waitForSessionGeneration returns false on epoch change, but the lock callback does not distinguish cancellation from timeout. performRefresh captures the now-current epoch, so a successful response passes its fence and setSession resets signedOut. The fixture observes an actual refresh POST invocation after sign-out and signedIn=true afterward. A successful response is possible if server revocation has not completed or a later login installs a new cookie. The existing response-in-flight tests do not cover cancellation before dispatch.
  4. Server-side revocation: with no browser generation change, the restored document probes /account using the held credential; a 401 triggers the shared recovery, refresh rejects, and the fixture confirms clearing. A browser cannot infer external revocation merely from its nonsecret generation. No claim that the server accepts a revoked token.
  5. Expired access credential: the fixture confirms /account 401, one successful refresh and one safe GET retry. No access expiry deadline is stored or checked proactively. A stale request is therefore possible even with the change; this is distinct from the generation-detectable rotation that 6fd2932 addresses.
  6. Two restored tabs racing: in the supported path, the default exclusive Web Lock encloses peer wait, cookie refresh, generation publication and account load. In a local fixture with asynchronous channel delivery and a serial lock, two stale documents restore, one rotates and the other adopts its successor; exactly one refresh POST and one active lock callback are observed. No same-cookie concurrent refresh is introduced by these commits in this path. Without either Locks or BroadcastChannel, coordination and this auth pageshow listener are disabled; independent per-tab refresh and the multiple-tabs-unsupported notice are the documented fallback. Real cookie replay and actual bfcache eligibility were not exercised in this review.

Credential handling

The reviewed auth store holds the access token in memory and stores only infraternal-session-generation in localStorage. BroadcastChannel session payloads deliberately contain an access token plus generation; no refresh token is sent. The shared storage key/origin channel is the expected trust boundary under §1.1. No new credential logging or access/refresh-token URLs were found in auth.svelte.ts, api.ts, the stream client, or the generated API client. Stream tickets are requested with a bearer header; only the separate short-lived stream ticket is placed in the WebSocket URL (packages/stream/src/index.ts:641–651), as §3.1 requires. packages/api-client/src/client.ts contains a generated openapi-fetch client without session coordination; the reviewed web runtime uses its own api.ts request wrapper and imports DTOs from api-client.

Closing and recreating a channel does not replay missed messages. The HTML Standard restricts eligible recipients and drops delivery to closed destinations; the application must reconcile missed sign-out separately from rotation. HTML Standard §9.5. The default exclusive Web Lock is held until its callback's promise settles. Web Locks request.

Verification and coverage limits

The existing auth.test.ts stubs window without addEventListener, so it never installs or exercises the new lifecycle handlers. The stream test change supplies an immediately resolved barrier and does not prove tickets wait for a delayed reconciliation. scripts/browser-check.mjs:2055 tests simultaneous first load, and :2081 tests sign-out after refresh dispatch using a held response; neither covers a missed sign-out followed by login or sign-out during the peer wait. Add regression coverage for both P1s and a delayed restore/API/stream barrier in the owning implementation job.

For this read-only review, compile.mjs strips TypeScript with Bun and compiles the unchanged auth source with the already-installed Svelte 5.57.1 compiler (matching the reviewed dependency version). It writes generated review modules externally; check.mjs injects lifecycle events, peer messages and HTTP failure/success responses, including a serial-lock model for two documents. These are local diagnostics, not production-browser evidence or merge approval. No scripts/verify gate, Rust build, full Vitest suite, or production-browser smoke was run. The instructed read-only scope and no-Rust-build limit were preserved. No commits or pushes.

The repository had no code-review-graph database. It was built into the external job directory (346 files, 5019 nodes, 67982 edges); auth function/edge queries supplied dependency evidence without writing source files. Source reads used the explicit diff paths and fallback rg while that index was unavailable.

Command: nice -n 15 bun /mnt/hdd/infraternal/jobs/review-port-auth/check.mjs

PASS rotation restore: adopted peer credential; zero old-credential requests and zero refresh POSTs.
PASS completed server sign-out restore: old /account is attempted then refresh rejects and tab clears.
CONFIRMED missed-signout defect: restored tab adopts later login without a local passkey ceremony.
CONFIRMED peer-wait signout defect: refresh POST starts after sign-out, accepts successful response and restores session.
CONFIRMED restore barrier gap: ordinary API sends old credential while peer handoff is pending.
PASS expired restore: initial old-token /account rejects; one refresh and safe GET retry recover.
PASS revoked restore: initial old-token /account rejects; refresh rejects; tab clears.
PASS two restored tabs: serial lock and delayed peer delivery yield one refresh and a shared successor credential.
Review checks: 5 boundary checks passed; 3 defects confirmed with failure injection. No real credentials used.
Exit status: 0

Artifacts: findings.md, compile.mjs, check.mjs, checks.log and graph-auth-edges.txt in /mnt/hdd/infraternal/jobs/review-port-auth. All values used by the fixture are synthetic and are not printed.

Finished read-only review at unchanged HEAD 38ddd3da756de99a25381e0491f68b64fb277ce7. Verdict: do not merge. No commits or source changes. # review-port-auth HEAD: 38ddd3da756de99a25381e0491f68b64fb277ce7 (detached; calternal-port history). Read-only review of 6fd2932 and 428bad9 plus surrounding auth/API/stream code. No source edits or commits. Verdict: **do not merge**. - **Major / P1** — `packages/web/src/lib/auth.svelte.ts:104` (also :302, :317): a cached tab misses sign-out and adopts a later sign-in from another tab, violating the local-passkey-only re-entry contract; persist a nonsecret monotonic sign-out epoch, check it before restore/peer adoption/refresh, and bind session messages and refresh work to that epoch. - **Major / P1** — `packages/web/src/lib/auth.svelte.ts:200` (also :209, :146): sign-out during the 250 ms peer wait wakes the waiter but falls through to a new refresh using the post-sign-out epoch, allowing a successful response to restore the session; recheck the original epoch after every await and pass that epoch into performRefresh instead of recapturing it. - **Follow-up / P2** — `packages/web/src/lib/api.ts:27` (also auth.svelte.ts:104 and stream-attachment.svelte.ts:86): ordinary API calls bypass the restored-page barrier and can send the old access credential during peer handoff; gate authenticated API dispatch on restore reconciliation and acquire the current credential afterward, keeping reconciliation's own requests exempt to avoid recursion. ## Concrete scenarios and impact 1. **Refresh rotated in another tab while cached:** pagehide closes the channel; storage advances; persisted pageshow asks a live peer under the refresh lock. With a current peer reply, the restored tab adopts the newer credential, sends no held-token /account request, and does not rotate the cookie. The fixture confirms this. Stream resume waits on afterPageShowRevalidation; auth's listener is registered before stream's listener through its static import. Ordinary inventory/API dispatch has no such barrier (P2 above). 2. **Sign-out while cached, no later login:** no sign-out epoch or tombstone is stored. The restored tab first sends its held credential to /account because sign-out does not advance the stored session generation. With completed server revocation, /account and refresh return 401 and the tab clears. This uses a revoked credential on the wire but does not bypass server authorization. If another tab completes a later sign-in before restore, the frozen tab instead adopts the new credential (or refreshes the new cookie after peer timeout), without a local ceremony: P1 above. This also permits an account change in a previously authenticated document. 3. **Sign-out during peer wait:** waitForSessionGeneration returns false on epoch change, but the lock callback does not distinguish cancellation from timeout. performRefresh captures the now-current epoch, so a successful response passes its fence and setSession resets signedOut. The fixture observes an actual refresh POST invocation after sign-out and signedIn=true afterward. A successful response is possible if server revocation has not completed or a later login installs a new cookie. The existing response-in-flight tests do not cover cancellation before dispatch. 4. **Server-side revocation:** with no browser generation change, the restored document probes /account using the held credential; a 401 triggers the shared recovery, refresh rejects, and the fixture confirms clearing. A browser cannot infer external revocation merely from its nonsecret generation. No claim that the server accepts a revoked token. 5. **Expired access credential:** the fixture confirms /account 401, one successful refresh and one safe GET retry. No access expiry deadline is stored or checked proactively. A stale request is therefore possible even with the change; this is distinct from the generation-detectable rotation that 6fd2932 addresses. 6. **Two restored tabs racing:** in the supported path, the default exclusive Web Lock encloses peer wait, cookie refresh, generation publication and account load. In a local fixture with asynchronous channel delivery and a serial lock, two stale documents restore, one rotates and the other adopts its successor; exactly one refresh POST and one active lock callback are observed. No same-cookie concurrent refresh is introduced by these commits in this path. Without either Locks or BroadcastChannel, coordination and this auth pageshow listener are disabled; independent per-tab refresh and the multiple-tabs-unsupported notice are the documented fallback. Real cookie replay and actual bfcache eligibility were not exercised in this review. ## Credential handling The reviewed auth store holds the access token in memory and stores only infraternal-session-generation in localStorage. BroadcastChannel session payloads deliberately contain an access token plus generation; no refresh token is sent. The shared storage key/origin channel is the expected trust boundary under §1.1. No new credential logging or access/refresh-token URLs were found in auth.svelte.ts, api.ts, the stream client, or the generated API client. Stream tickets are requested with a bearer header; only the separate short-lived stream ticket is placed in the WebSocket URL (packages/stream/src/index.ts:641–651), as §3.1 requires. packages/api-client/src/client.ts contains a generated openapi-fetch client without session coordination; the reviewed web runtime uses its own api.ts request wrapper and imports DTOs from api-client. Closing and recreating a channel does not replay missed messages. The HTML Standard restricts eligible recipients and drops delivery to closed destinations; the application must reconcile missed sign-out separately from rotation. [HTML Standard §9.5](https://html.spec.whatwg.org/multipage/web-messaging.html#broadcasting-to-other-browsing-contexts). The default exclusive Web Lock is held until its callback's promise settles. [Web Locks request](https://www.w3.org/TR/web-locks/#api-lockmanager-request). ## Verification and coverage limits The existing auth.test.ts stubs window without addEventListener, so it never installs or exercises the new lifecycle handlers. The stream test change supplies an immediately resolved barrier and does not prove tickets wait for a delayed reconciliation. scripts/browser-check.mjs:2055 tests simultaneous first load, and :2081 tests sign-out after refresh dispatch using a held response; neither covers a missed sign-out followed by login or sign-out during the peer wait. Add regression coverage for both P1s and a delayed restore/API/stream barrier in the owning implementation job. For this read-only review, compile.mjs strips TypeScript with Bun and compiles the unchanged auth source with the already-installed Svelte 5.57.1 compiler (matching the reviewed dependency version). It writes generated review modules externally; check.mjs injects lifecycle events, peer messages and HTTP failure/success responses, including a serial-lock model for two documents. These are local diagnostics, not production-browser evidence or merge approval. No scripts/verify gate, Rust build, full Vitest suite, or production-browser smoke was run. The instructed read-only scope and no-Rust-build limit were preserved. No commits or pushes. The repository had no code-review-graph database. It was built into the external job directory (346 files, 5019 nodes, 67982 edges); auth function/edge queries supplied dependency evidence without writing source files. Source reads used the explicit diff paths and fallback rg while that index was unavailable. Command: `nice -n 15 bun /mnt/hdd/infraternal/jobs/review-port-auth/check.mjs` ```text PASS rotation restore: adopted peer credential; zero old-credential requests and zero refresh POSTs. PASS completed server sign-out restore: old /account is attempted then refresh rejects and tab clears. CONFIRMED missed-signout defect: restored tab adopts later login without a local passkey ceremony. CONFIRMED peer-wait signout defect: refresh POST starts after sign-out, accepts successful response and restores session. CONFIRMED restore barrier gap: ordinary API sends old credential while peer handoff is pending. PASS expired restore: initial old-token /account rejects; one refresh and safe GET retry recover. PASS revoked restore: initial old-token /account rejects; refresh rejects; tab clears. PASS two restored tabs: serial lock and delayed peer delivery yield one refresh and a shared successor credential. Review checks: 5 boundary checks passed; 3 defects confirmed with failure injection. No real credentials used. Exit status: 0 ``` Artifacts: findings.md, compile.mjs, check.mjs, checks.log and graph-auth-edges.txt in /mnt/hdd/infraternal/jobs/review-port-auth. All values used by the fixture are synthetic and are not printed.
Author
Owner

Started defensive re-review at detached HEAD 02de1a9213 (calternal-port), reviewing fix diff from 38ddd3da75. Scope: auth/session epoch and authenticated dispatch gate; read-mostly, no commits, bun/Vitest diagnostics only at nice 15. Findings will be written to /mnt/hdd/infraternal/jobs/rereview-port-auth/findings.md.

Started defensive re-review at detached HEAD 02de1a92137bce09dadc95ee6544c207e40d31ed (calternal-port), reviewing fix diff from 38ddd3da756de99a25381e0491f68b64fb277ce7. Scope: auth/session epoch and authenticated dispatch gate; read-mostly, no commits, bun/Vitest diagnostics only at nice 15. Findings will be written to /mnt/hdd/infraternal/jobs/rereview-port-auth/findings.md.
Author
Owner

rereview-port-auth

HEAD: 02de1a92137bce09dadc95ee6544c207e40d31ed (detached, calternal-port). Reviewed git diff 38ddd3d 02de1a9, the previous findings, and surrounding auth/API/sidebar sign-out code against the operating contract and docs/contracts.md §1.1. No source changes, commits or pushes.

Verdict: do not merge.

  • Major / P1, blocks merge — packages/web/src/lib/auth.svelte.ts:384 (also packages/web/src/lib/api.ts:46): sign-out during restore clears the session before its revocation POST passes the new gate, so the gate returns null and rejects locally with 401; no server revocation is sent.
  • Major / P1, blocks merge — packages/web/src/lib/auth.svelte.ts:47 (also :46, :56, :61): unavailable or invalidated epoch storage is treated as an unchanged boundary, allowing a frozen document to refresh into a later shared-cookie session without its own passkey ceremony.
  • Follow-up / P2 — packages/web/src/lib/api.ts:46 (also packages/web/src/lib/auth.svelte.ts:155, :163, :260): gate waits have no deadline or AbortSignal handling and do not settle on session clear; stalled reconciliation can hold every gated call indefinitely, including an aborted request.

Prior findings

  1. Missed sign-out with intact storage: closed. The restored document observes the higher epoch, clears before HTTP or peer adoption, and cannot refresh again. Messages are restricted to the document's accepted boundary. The prior scenario passes with the persisted epoch added to its fixture. This guarantee fails under the storage conditions in the second P1 above.
  2. Sign-out during peer wait: closed. The original in-memory epoch is rechecked after the wait; performRefresh receives that original epoch and refuses dispatch after cancellation. Injecting the sign-out broadcast during the wait yields false and zero refresh POSTs.
  3. Ordinary API dispatch during restore: closed on successful reconciliation. An inventory call waits during peer handoff and uses the adopted credential. The auth store's account request bypasses the gate; a restore account 401 followed by successful refresh/account/retry settles without direct gate recursion. The first P1 is a new sign-out interaction introduced by this gate.

The original prior-review fixture was rerun against source extracted from 38ddd3d into the external job directory: all three prior defects were reproduced, and its five other boundary checks passed. Source at 02de1a9 was compiled unchanged with Bun's TypeScript transpiler and the installed Svelte compiler for the new diagnostic fixture.

Evidence for remaining findings

Revocation skipped during restore. Start with an authenticated document, hide/restore it, and hold its /account reconciliation response. Invoke local sign-out with no preference writes pending. Local state clears, but /auth/signout enters the authenticated dispatch gate and waits. Release the successful account response: reconciliation settles, the gate sees signedOut and returns null, and sign-out rejects locally with ApiRequestError status 401. The fixture observes zero sign-out POSTs both before and after release. The server never receives this revocation request; local clearing alone does not revoke its session family. Reconciliation traffic should remain gated, but explicit revocation must reach the server with a usable credential through a separately defined path. Add coverage with and without pending sidebar writes.

Storage failures fail open. With storage reads/writes throwing, local passkey sign-in and normal local sign-out work; the exceptions are caught. However, a cached document that missed another tab's sign-out sees its own knownSignOutEpoch from the catch branch, so signOutMissed is false. Inject rejection of the old account credential and successful refresh/account responses representing a later passkey login in another tab: the frozen document becomes signed in under the new credential. No local ceremony occurs. Swallowing the epoch write failure similarly leaves no persistent evidence for the cached document. sharedRefresh/singleTabNotice checks only Locks and BroadcastChannel, not functioning persistent epoch storage.

The fixture also confirms that removing the epoch, lowering it to the old boundary, or making it invalid permits later-cookie adoption. Missing/invalid values become zero; the comparison rejects only a higher value. An intact higher epoch prevents this. A high forged epoch can force local clearing; an epoch alone cannot manufacture a server credential. Same-origin code that can forge storage/messages already lies inside this client's trust boundary, so this is a continuity failure, not evidence of third-party token forgery or bypass of server authorization. Treat uncertain storage continuity as requiring local re-entry, or provide a separate reliable boundary mechanism; never silently claim the persistent guarantee when storage is unavailable.

The HTML Standard permits the localStorage getter to throw SecurityError and setItem to fail, including for disabled storage or quota exhaustion. This review injects those failures; it does not claim that every private-browsing implementation disables storage. HTML Standard, Web storage, Storage interface.

Unbounded gate lifetime. Hold reconciliation's account fetch; issue an authenticated inventory call with an AbortSignal, abort it, and clear auth state. The call stays pending until the held account response is released, then rejects. The application supplies neither a bounded account/refresh deadline nor cancellation for the queued refresh lock. The 250 ms peer timeout does not bound lock acquisition or network I/O. A never-settling dependency leaves restoring set and all such calls held; sidebar flushes can also wait there before local sign-out clearing. The direct account bypass avoids the normal nested gate cycle, but does not solve dependency lifetime. Web Locks explicitly supports cancellation of a queued request through an optional signal; this call supplies none. Web Locks request options.

Credential handling

The epoch and session generation stored in localStorage are nonsecret numeric counters. session_request messages carry generation and signOutEpoch; signout messages contain only their type. session messages do contain the access credential, as they already did before these fixes, plus the generation and new nonsecret epoch. No refresh credential is distributed in these messages or persisted by this auth code. No new credential logging was found. The epoch is a coordination boundary, not an authentication credential.

Verification

All Bun/Vitest execution used nice -n 15. Installed this worktree's dependencies with bun install --frozen-lockfile; the first Vitest attempt lacked dependencies and exited 127, then the actual targeted run below passed. No lockfile or tracked source changes resulted.

Command: nice -n 15 bun run --cwd packages/web test src/lib/auth.test.ts src/lib/auth.svelte.test.ts src/lib/api.test.ts

 RUN  v5.0.1 /mnt/hdd/infraternal/wt-lp/rereview-port-auth/packages/web

 Test Files  3 passed (3)
      Tests  31 passed (31)
   Start at  11:28:27
   Duration  4.79s (tests 50%, transform 39%, import 10%, worker 1%)

Exit status: 0. Full output: vitest.log in this job directory.

Command: nice -n 15 bun /mnt/hdd/infraternal/jobs/rereview-port-auth/check.mjs

PASS prior missed-signout scenario: intact epoch clears before any HTTP dispatch.
PASS prior peer-wait cancellation: no refresh dispatch after sign-out.
PASS prior API barrier scenario: current peer credential used after reconciliation.
CONFIRMED storage-unavailable fail-open: frozen document refreshes later cookie without local ceremony.
CONFIRMED epoch continuity loss: removed, lowered and invalid epoch each allow later-cookie adoption.
CONFIRMED sign-out gate regression: local session clears but revocation POST is rejected locally with 401.
CONFIRMED unbounded gate wait: aborted call remains pending after session clear until account fetch settles.
PASS nested account recovery: bypass avoids dispatch-gate recursion on restore 401.
Diagnostic checks completed; synthetic values only, no real credentials used.
PASS local passkey and local sign-out with throwing storage outside restore: no storage exception escapes.

Exit status: 0. Fixtures are controlled local diagnostics, not production-browser evidence. No real WebAuthn, cookies, bfcache eligibility, browser matrix, scripts/verify gate, Rust build or performance measurement was run under this bun/Vitest-only job scope. Passing targeted tests does not establish merge-gate approval.

The code-review graph was absent and was built externally (346 files, 5031 nodes, 68206 edges). Auth function/call-edge evidence is in graph-auth.txt; source searches were used where the graph was unavailable or insufficient. Other artifacts: compile.mjs, check.mjs, checks.log, vitest.log, old-checks.log, and extracted old source/compiled fixture under source-old/ and old/. Final git diff and status are clean; HEAD remains unchanged.

# rereview-port-auth HEAD: `02de1a92137bce09dadc95ee6544c207e40d31ed` (detached, calternal-port). Reviewed `git diff 38ddd3d 02de1a9`, the previous findings, and surrounding auth/API/sidebar sign-out code against the operating contract and docs/contracts.md §1.1. No source changes, commits or pushes. Verdict: **do not merge**. - **Major / P1, blocks merge** — `packages/web/src/lib/auth.svelte.ts:384` (also `packages/web/src/lib/api.ts:46`): sign-out during restore clears the session before its revocation POST passes the new gate, so the gate returns null and rejects locally with 401; no server revocation is sent. - **Major / P1, blocks merge** — `packages/web/src/lib/auth.svelte.ts:47` (also :46, :56, :61): unavailable or invalidated epoch storage is treated as an unchanged boundary, allowing a frozen document to refresh into a later shared-cookie session without its own passkey ceremony. - **Follow-up / P2** — `packages/web/src/lib/api.ts:46` (also `packages/web/src/lib/auth.svelte.ts:155`, :163, :260): gate waits have no deadline or AbortSignal handling and do not settle on session clear; stalled reconciliation can hold every gated call indefinitely, including an aborted request. ## Prior findings 1. **Missed sign-out with intact storage: closed.** The restored document observes the higher epoch, clears before HTTP or peer adoption, and cannot refresh again. Messages are restricted to the document's accepted boundary. The prior scenario passes with the persisted epoch added to its fixture. This guarantee fails under the storage conditions in the second P1 above. 2. **Sign-out during peer wait: closed.** The original in-memory epoch is rechecked after the wait; performRefresh receives that original epoch and refuses dispatch after cancellation. Injecting the sign-out broadcast during the wait yields false and zero refresh POSTs. 3. **Ordinary API dispatch during restore: closed on successful reconciliation.** An inventory call waits during peer handoff and uses the adopted credential. The auth store's account request bypasses the gate; a restore account 401 followed by successful refresh/account/retry settles without direct gate recursion. The first P1 is a new sign-out interaction introduced by this gate. The original prior-review fixture was rerun against source extracted from `38ddd3d` into the external job directory: all three prior defects were reproduced, and its five other boundary checks passed. Source at `02de1a9` was compiled unchanged with Bun's TypeScript transpiler and the installed Svelte compiler for the new diagnostic fixture. ## Evidence for remaining findings **Revocation skipped during restore.** Start with an authenticated document, hide/restore it, and hold its `/account` reconciliation response. Invoke local sign-out with no preference writes pending. Local state clears, but `/auth/signout` enters the authenticated dispatch gate and waits. Release the successful account response: reconciliation settles, the gate sees signedOut and returns null, and sign-out rejects locally with ApiRequestError status 401. The fixture observes zero sign-out POSTs both before and after release. The server never receives this revocation request; local clearing alone does not revoke its session family. Reconciliation traffic should remain gated, but explicit revocation must reach the server with a usable credential through a separately defined path. Add coverage with and without pending sidebar writes. **Storage failures fail open.** With storage reads/writes throwing, local passkey sign-in and normal local sign-out work; the exceptions are caught. However, a cached document that missed another tab's sign-out sees its own knownSignOutEpoch from the catch branch, so signOutMissed is false. Inject rejection of the old account credential and successful refresh/account responses representing a later passkey login in another tab: the frozen document becomes signed in under the new credential. No local ceremony occurs. Swallowing the epoch write failure similarly leaves no persistent evidence for the cached document. sharedRefresh/singleTabNotice checks only Locks and BroadcastChannel, not functioning persistent epoch storage. The fixture also confirms that removing the epoch, lowering it to the old boundary, or making it invalid permits later-cookie adoption. Missing/invalid values become zero; the comparison rejects only a higher value. An intact higher epoch prevents this. A high forged epoch can force local clearing; an epoch alone cannot manufacture a server credential. Same-origin code that can forge storage/messages already lies inside this client's trust boundary, so this is a continuity failure, not evidence of third-party token forgery or bypass of server authorization. Treat uncertain storage continuity as requiring local re-entry, or provide a separate reliable boundary mechanism; never silently claim the persistent guarantee when storage is unavailable. The HTML Standard permits the localStorage getter to throw SecurityError and setItem to fail, including for disabled storage or quota exhaustion. This review injects those failures; it does not claim that every private-browsing implementation disables storage. [HTML Standard, Web storage](https://html.spec.whatwg.org/multipage/webstorage.html#the-localstorage-attribute), [Storage interface](https://html.spec.whatwg.org/multipage/webstorage.html#the-storage-interface). **Unbounded gate lifetime.** Hold reconciliation's account fetch; issue an authenticated inventory call with an AbortSignal, abort it, and clear auth state. The call stays pending until the held account response is released, then rejects. The application supplies neither a bounded account/refresh deadline nor cancellation for the queued refresh lock. The 250 ms peer timeout does not bound lock acquisition or network I/O. A never-settling dependency leaves restoring set and all such calls held; sidebar flushes can also wait there before local sign-out clearing. The direct account bypass avoids the normal nested gate cycle, but does not solve dependency lifetime. Web Locks explicitly supports cancellation of a queued request through an optional signal; this call supplies none. [Web Locks request options](https://www.w3.org/TR/web-locks/#api-lockmanager-request). ## Credential handling The epoch and session generation stored in localStorage are nonsecret numeric counters. session_request messages carry generation and signOutEpoch; signout messages contain only their type. **session messages do contain the access credential**, as they already did before these fixes, plus the generation and new nonsecret epoch. No refresh credential is distributed in these messages or persisted by this auth code. No new credential logging was found. The epoch is a coordination boundary, not an authentication credential. ## Verification All Bun/Vitest execution used `nice -n 15`. Installed this worktree's dependencies with `bun install --frozen-lockfile`; the first Vitest attempt lacked dependencies and exited 127, then the actual targeted run below passed. No lockfile or tracked source changes resulted. Command: `nice -n 15 bun run --cwd packages/web test src/lib/auth.test.ts src/lib/auth.svelte.test.ts src/lib/api.test.ts` ```text RUN v5.0.1 /mnt/hdd/infraternal/wt-lp/rereview-port-auth/packages/web Test Files 3 passed (3) Tests 31 passed (31) Start at 11:28:27 Duration 4.79s (tests 50%, transform 39%, import 10%, worker 1%) ``` Exit status: 0. Full output: `vitest.log` in this job directory. Command: `nice -n 15 bun /mnt/hdd/infraternal/jobs/rereview-port-auth/check.mjs` ```text PASS prior missed-signout scenario: intact epoch clears before any HTTP dispatch. PASS prior peer-wait cancellation: no refresh dispatch after sign-out. PASS prior API barrier scenario: current peer credential used after reconciliation. CONFIRMED storage-unavailable fail-open: frozen document refreshes later cookie without local ceremony. CONFIRMED epoch continuity loss: removed, lowered and invalid epoch each allow later-cookie adoption. CONFIRMED sign-out gate regression: local session clears but revocation POST is rejected locally with 401. CONFIRMED unbounded gate wait: aborted call remains pending after session clear until account fetch settles. PASS nested account recovery: bypass avoids dispatch-gate recursion on restore 401. Diagnostic checks completed; synthetic values only, no real credentials used. PASS local passkey and local sign-out with throwing storage outside restore: no storage exception escapes. ``` Exit status: 0. Fixtures are controlled local diagnostics, not production-browser evidence. No real WebAuthn, cookies, bfcache eligibility, browser matrix, scripts/verify gate, Rust build or performance measurement was run under this bun/Vitest-only job scope. Passing targeted tests does not establish merge-gate approval. The code-review graph was absent and was built externally (346 files, 5031 nodes, 68206 edges). Auth function/call-edge evidence is in `graph-auth.txt`; source searches were used where the graph was unavailable or insufficient. Other artifacts: `compile.mjs`, `check.mjs`, `checks.log`, `vitest.log`, `old-checks.log`, and extracted old source/compiled fixture under `source-old/` and `old/`. Final git diff and status are clean; HEAD remains unchanged.
Author
Owner

Starting defensive re-review round 3 for issue #46. Worktree rereview2-port-auth; detached calternal-port HEAD/base 62bad5c7ac. Review diff 02de1a9..62bad5c and round-1/round-2 diagnostics. No commits or pushes; Bun/Vitest only with nice -n 15. Findings will be recorded in the external job directory.

Starting defensive re-review round 3 for issue #46. Worktree rereview2-port-auth; detached calternal-port HEAD/base 62bad5c7acac6633305bb83598a62bb3473cd183. Review diff 02de1a9..62bad5c and round-1/round-2 diagnostics. No commits or pushes; Bun/Vitest only with nice -n 15. Findings will be recorded in the external job directory.
Author
Owner

Round-3 defensive review findings at 62bad5c (no source changes):

  • P1 packages/web/src/lib/auth.svelte.ts:109 ignores failed epoch write. A write-only failure leaves a readable unchanged boundary in storage; a frozen document remains eligible to resume after another document signs out and completes a later passkey sign-in. Read failures and removed/lowered/invalid entries now fail closed, but the round-2 epoch issue is only partially closed. Local diagnostic evidence in checks.log.
  • P1 packages/web/src/lib/auth.svelte.ts:452 times out reconciliation and then uses the held access credential for sign-out. After completed rotation, this credential is revoked; the server sign_out authenticates before revocation (crates/server/src/auth.rs:1153), so it refuses this request. Local state also stays signed in during the 10-second wait. Completed-reconciliation revocation now dispatches correctly.
  • Existing web Vitest suite: 13 files / 77 tests passed (nice -n 15). Prior missed-sign-out, peer-wait cancellation, API gate, expired/revoked restore, two-document rotation, document-local lifecycle, abort and clear checks pass. Verification is local Bun/Vitest evidence only; no production/browser/Rust/perf gates run in this job.
Round-3 defensive review findings at 62bad5c (no source changes): - P1 packages/web/src/lib/auth.svelte.ts:109 ignores failed epoch write. A write-only failure leaves a readable unchanged boundary in storage; a frozen document remains eligible to resume after another document signs out and completes a later passkey sign-in. Read failures and removed/lowered/invalid entries now fail closed, but the round-2 epoch issue is only partially closed. Local diagnostic evidence in checks.log. - P1 packages/web/src/lib/auth.svelte.ts:452 times out reconciliation and then uses the held access credential for sign-out. After completed rotation, this credential is revoked; the server sign_out authenticates before revocation (crates/server/src/auth.rs:1153), so it refuses this request. Local state also stays signed in during the 10-second wait. Completed-reconciliation revocation now dispatches correctly. - Existing web Vitest suite: 13 files / 77 tests passed (nice -n 15). Prior missed-sign-out, peer-wait cancellation, API gate, expired/revoked restore, two-document rotation, document-local lifecycle, abort and clear checks pass. Verification is local Bun/Vitest evidence only; no production/browser/Rust/perf gates run in this job.
Author
Owner

rereview2-port-auth — defensive re-review round 3

HEAD: 62bad5c7acac6633305bb83598a62bb3473cd183 (detached, calternal-port). Reviewed 02de1a9..62bad5c, the round-1 and round-2 findings and diagnostics, and surrounding server authentication, shell sign-out, sidebar persistence, polling and stream recovery. No tracked source changes, commits or pushes.

Verdict: do not merge.

  • Major / P1, blocks merge — packages/web/src/lib/auth.svelte.ts:109 (also :95, :121): failed epoch writes leave a readable unchanged boundary, so a frozen document can resume a later shared-cookie session without a local passkey ceremony; the round-2 continuity finding is only partially closed.
  • Major / P1, blocks merge — packages/web/src/lib/auth.svelte.ts:452 (also :453, :464): sign-out after reconciliation timeout sends the held, potentially rotated/revoked credential and cannot revoke its successor; local sign-out also waits the full 10 seconds.
  • Follow-up / P2 — packages/web/src/lib/visible-poller.ts:55 (also :38, :59; packages/web/src/lib/api.ts:46): interval ticks suppress the restore-timeout error and immediately queue another 10-second wait, so inventory can remain stale/loading without reaching its delayed/error UI.

Round-2 closure

  1. Sign-out during reconciliation: partially closed. Re-running the held-account-response injection now produces one sign-out POST through the bypass when reconciliation completes. It is no longer rejected locally by the cleared gate. However, a stalled rotation exceeding the deadline still results in an unusable revocation credential; see the P1 below. Pending sidebar flushes remain awaited before the 10-second sign-out wait begins, so the bound does not cover the whole sign-out operation. The existing preference-flush tests pass.
  2. Epoch storage continuity: partially closed. Unreadable storage now prevents refresh dispatch. Removed, lowered, invalid, noncanonical and unsafe epoch values differing from the accepted boundary end a frozen session before HTTP dispatch, and subsequent refresh cannot re-enter. A passkey ceremony with unusable storage creates a document-local session, publishes no access-credential session messages, and cannot resume after pagehide/pageshow, including without Web Locks. Write-only failure with still-readable old storage is not closed.
  3. Unbounded/aborted dispatch wait: closed for the reported caller lifetime. Abort rejects promptly; clear releases other gated calls with 401; a stalled gate rejects after 10 seconds with 503 session_restoring. The stream barrier also settles at that bound. These deadlines do not cancel the underlying network reconciliation or queued lock acquisition; the polling follow-up below describes the remaining UI interaction.

Evidence for P1: unchanged boundary after failed write

recordSignOut() ignores the boolean returned by writeSignOutEpoch(). It invalidates only the signing-out document's known boundary. If getItem() still returns the old canonical integer while setItem() fails, a frozen document that closed its channel sees precisely its accepted value at :95. A subsequent local passkey ceremony in the other document also accepts that old readable value at :121 without verifying a new write, so the sessions still appear eligible for peer exchange and shared-cookie recovery.

The external Bun diagnostic uses two auth-store instances and shared synthetic storage. One document is frozen; the other signs out with an injected epoch-write QuotaExceededError while reads remain available, then completes a synthetic local ceremony. The persisted boundary stays unchanged and the cached document resumes. The no-resurrection requirement is therefore not established by readback equality alone. Cover write-only failures and ensure a later sign-in cannot reuse a boundary whose sign-out publication failed.

This is a client continuity failure, not server authorization bypass or a claim of credential forgery. A failed storage write is a supported failure mode: the HTML Standard specifies that setItem() can throw when a value cannot be stored; it does not require getItem() to fail with it. HTML Standard, Storage interface.

A related limitation is reinitializing a missing key to the reusable value zero (:88 and :119). Equality cannot detect a missed increase if another document later recreates the entry with an old document's original boundary. The removed/lowered tests exercise a value differing from the document's boundary; they do not prove continuity after another document recreates it. This is additional static reasoning under the same P1, not separately verified browser evidence.

Evidence for P1: sign-out timeout and delayed local clear

The timeout in :452 merely ends the wait. It does not distinguish successful reconciliation from a deadline; :453 takes whichever access token is still held. When another tab has completed rotation, that old token is already revoked by contract. crates/server/src/auth.rs:1153 authenticates the sign-out bearer before revocation, and crates/server/src/storage/mod.rs:1272 refuses inactive access credentials. Consequently this POST cannot revoke the current session or reach the successful response that expires the refresh cookie. After clear(), unauthorized recovery cannot obtain a successor because refreshSession() refuses a signed-out document.

The local diagnostic holds restore refresh beyond the real 10-second deadline and injects the expected old-token 401 at sign-out. The document remains signedIn=true during the wait, dispatches sign-out with the held token at the deadline, clears locally, and rejects with 401. A late refresh response cannot restore it, but no revocation with the successor occurs. The server's actual refusal follows from source and the contract; this job did not run a live server. This is failure to revoke, not evidence that the server accepts a revoked credential.

The shell calls void authStore.signOut() without a rejection handler (packages/web/src/lib/shell/AuthenticatedShellBody.svelte:183, :201), so that rejection is also unsurfaced. busy=true does not clear the shell or its session consumers. Local clearing and the server revocation lifecycle need independent handling so a stalled restore does not leave the person visibly signed in and lose the usable revocation credential. Pending sidebar network writes can extend the delay further because :441 has no whole-operation deadline.

Restore-timeout UI follow-up

The API wrapper does not automatically retry 503, so there is no immediate request-wrapper retry loop. The gate remains open while the actual reconciliation is pending, however. Dashboard polling runs every 2 seconds. Each tick increments the poller's generation before noticing its request is already in flight (:38–42). At the 10-second gate rejection, the saved request generation is stale, so :55 skips onError; :59 starts the queued follow-up, which enters the same gate again. Continued ticks repeat this behavior.

A separate Bun diagnostic using unchanged compiled api.ts and visible-poller.ts observes two polling requests and zero onError calls after 12.1 seconds with a held gate and the actual 2-second interval. No fetch is dispatched. Dashboard's delayed announcement/error state is set only in onError (packages/web/src/routes/+page.svelte:54); initial/manual loading or a prior Live inventory indicator can therefore persist. This is source plus local timer evidence, not production-browser rendering evidence. When reconciliation eventually completes, ordinary retry can recover; indefinitely pending reconciliation requires sign-out/re-entry or reload.

Round-1 regression checks and credentials

The local fixture confirms that an intact advanced epoch ends a cached session before any HTTP dispatch; sign-out during peer wait cancels refresh without falling through; inventory dispatch waits for peer reconciliation and takes the successor; expired-account recovery does not recurse through the gate; server-rejection injection clears auth; and two restored documents using a serial lock and delayed peer messages produce one rotation and share the successor.

No new credential persistence or logging was found. localStorage contains only the numeric generation and sign-out epoch. BroadcastChannel session messages deliberately contain the access credential in addition to those counters, as before these fixes and as specified in contracts §1.1. Session requests carry counters; sign-out messages carry only their type. No refresh credential is stored or broadcast by this auth code. The document-local boundary does not serialize the string local, publish an access credential, or answer peer session requests (exchangeEpoch() is null); its fresh shared HttpOnly cookie still affects later refreshes, which is why the failed-write P1 matters. Stream URLs use the separate stream ticket, not an access or refresh credential.

Verification

All Bun/Vitest execution used nice -n 15. The first Vitest attempt exited 127 because dependencies were absent. bun install --frozen-lockfile succeeded with no tracked changes, then the full web suite passed.

Command: nice -n 15 bun run --cwd packages/web test

 RUN  v5.0.1 /mnt/hdd/infraternal/wt-lp/rereview2-port-auth/packages/web

 Test Files  13 passed (13)
      Tests  77 passed (77)
   Start at  11:44:12
   Duration  3.63s (transform 58%, tests 32%, import 8%, worker 1%)

Exit status: 0. Full output: vitest.log.

Command: nice -n 15 bun /mnt/hdd/infraternal/jobs/rereview2-port-auth/check.mjs

PASS prior missed-signout scenario: intact epoch clears before any HTTP dispatch.
PASS prior peer-wait cancellation: no refresh dispatch after sign-out.
PASS prior API barrier scenario: current peer credential used after reconciliation.
PASS unreadable storage: no refresh dispatch or session adoption.
PASS removed/lowered/invalid/noncanonical/unsafe epoch: frozen session ends before dispatch.
PASS sign-out during completed reconciliation: revocation POST reaches dispatch bypass.
PASS stalled reconciliation: abort rejects promptly; session clear releases other callers.
PASS expired restore: account 401 recovers and retries without gate recursion.
PASS server revocation: account and refresh rejection clear the session.
PASS document-local passkey boundary: no credential messages; frozen session clears with and without Locks.
PASS two restored documents: serial lock gives one rotation and shared successor.
PASS timeout contract: API returns session_restoring 503, stream wait settles, late refresh cannot restore.
OBSERVED sign-out limitation: local state waits 10 seconds; timed-out rotation sends held credential, server rejection surfaces.
Local diagnostic checks completed; synthetic values only.
OBSERVED epoch continuity gap: failed sign-out write leaves the readable boundary unchanged; cached document remains eligible to resume.

Exit status: 0. Source was compiled unchanged into external artifacts with Bun and the installed Svelte compiler. Prior diagnostics were adapted to assert fixed behavior and supply the accepted persisted epoch. All fixture credentials and ceremonies were synthetic; no real credentials were used or printed.

Command: nice -n 15 bun /mnt/hdd/infraternal/jobs/rereview2-port-auth/poller-check.mjs

OBSERVED polling interaction: 10-second gate error is suppressed after 2-second poll ticks; second wait starts, onError remains uncalled.

Exit status: 0. These are diagnostic checks, not a scripts/verify gate. No Rust build, live-server test, production-browser smoke, actual WebAuthn/bfcache test, browser matrix or performance measurement was run under this Bun/Vitest-only scope. Required merge-gate approval remains with the verification job.

Graph orientation used the prior round's external graph (auth, server sign-out, sidebar flush, polling and stream recovery nodes; graph-orientation.txt). A rebuild into this job's external graph directory was started because auth was stale, but stopped incomplete after slow filesystem traversal on the loaded VM; current auth evidence comes from the exact diff and source reads. No repo index/source was modified. Artifacts are contained in this job directory. Final git status is clean and HEAD is unchanged.

# rereview2-port-auth — defensive re-review round 3 HEAD: `62bad5c7acac6633305bb83598a62bb3473cd183` (detached, calternal-port). Reviewed `02de1a9..62bad5c`, the round-1 and round-2 findings and diagnostics, and surrounding server authentication, shell sign-out, sidebar persistence, polling and stream recovery. No tracked source changes, commits or pushes. Verdict: **do not merge**. - **Major / P1, blocks merge** — `packages/web/src/lib/auth.svelte.ts:109` (also :95, :121): failed epoch writes leave a readable unchanged boundary, so a frozen document can resume a later shared-cookie session without a local passkey ceremony; the round-2 continuity finding is only partially closed. - **Major / P1, blocks merge** — `packages/web/src/lib/auth.svelte.ts:452` (also :453, :464): sign-out after reconciliation timeout sends the held, potentially rotated/revoked credential and cannot revoke its successor; local sign-out also waits the full 10 seconds. - **Follow-up / P2** — `packages/web/src/lib/visible-poller.ts:55` (also :38, :59; `packages/web/src/lib/api.ts:46`): interval ticks suppress the restore-timeout error and immediately queue another 10-second wait, so inventory can remain stale/loading without reaching its delayed/error UI. ## Round-2 closure 1. **Sign-out during reconciliation: partially closed.** Re-running the held-account-response injection now produces one sign-out POST through the bypass when reconciliation completes. It is no longer rejected locally by the cleared gate. However, a stalled rotation exceeding the deadline still results in an unusable revocation credential; see the P1 below. Pending sidebar flushes remain awaited before the 10-second sign-out wait begins, so the bound does not cover the whole sign-out operation. The existing preference-flush tests pass. 2. **Epoch storage continuity: partially closed.** Unreadable storage now prevents refresh dispatch. Removed, lowered, invalid, noncanonical and unsafe epoch values differing from the accepted boundary end a frozen session before HTTP dispatch, and subsequent refresh cannot re-enter. A passkey ceremony with unusable storage creates a document-local session, publishes no access-credential session messages, and cannot resume after pagehide/pageshow, including without Web Locks. Write-only failure with still-readable old storage is not closed. 3. **Unbounded/aborted dispatch wait: closed for the reported caller lifetime.** Abort rejects promptly; clear releases other gated calls with 401; a stalled gate rejects after 10 seconds with 503 `session_restoring`. The stream barrier also settles at that bound. These deadlines do not cancel the underlying network reconciliation or queued lock acquisition; the polling follow-up below describes the remaining UI interaction. ## Evidence for P1: unchanged boundary after failed write `recordSignOut()` ignores the boolean returned by `writeSignOutEpoch()`. It invalidates only the signing-out document's known boundary. If `getItem()` still returns the old canonical integer while `setItem()` fails, a frozen document that closed its channel sees precisely its accepted value at :95. A subsequent local passkey ceremony in the other document also accepts that old readable value at :121 without verifying a new write, so the sessions still appear eligible for peer exchange and shared-cookie recovery. The external Bun diagnostic uses two auth-store instances and shared synthetic storage. One document is frozen; the other signs out with an injected epoch-write `QuotaExceededError` while reads remain available, then completes a synthetic local ceremony. The persisted boundary stays unchanged and the cached document resumes. The no-resurrection requirement is therefore not established by readback equality alone. Cover write-only failures and ensure a later sign-in cannot reuse a boundary whose sign-out publication failed. This is a client continuity failure, not server authorization bypass or a claim of credential forgery. A failed storage write is a supported failure mode: the HTML Standard specifies that `setItem()` can throw when a value cannot be stored; it does not require `getItem()` to fail with it. [HTML Standard, Storage interface](https://html.spec.whatwg.org/multipage/webstorage.html#the-storage-interface). A related limitation is reinitializing a missing key to the reusable value zero (:88 and :119). Equality cannot detect a missed increase if another document later recreates the entry with an old document's original boundary. The removed/lowered tests exercise a value differing from the document's boundary; they do not prove continuity after another document recreates it. This is additional static reasoning under the same P1, not separately verified browser evidence. ## Evidence for P1: sign-out timeout and delayed local clear The timeout in :452 merely ends the wait. It does not distinguish successful reconciliation from a deadline; :453 takes whichever access token is still held. When another tab has completed rotation, that old token is already revoked by contract. `crates/server/src/auth.rs:1153` authenticates the sign-out bearer before revocation, and `crates/server/src/storage/mod.rs:1272` refuses inactive access credentials. Consequently this POST cannot revoke the current session or reach the successful response that expires the refresh cookie. After `clear()`, unauthorized recovery cannot obtain a successor because `refreshSession()` refuses a signed-out document. The local diagnostic holds restore refresh beyond the real 10-second deadline and injects the expected old-token 401 at sign-out. The document remains `signedIn=true` during the wait, dispatches sign-out with the held token at the deadline, clears locally, and rejects with 401. A late refresh response cannot restore it, but no revocation with the successor occurs. The server's actual refusal follows from source and the contract; this job did not run a live server. This is failure to revoke, not evidence that the server accepts a revoked credential. The shell calls `void authStore.signOut()` without a rejection handler (`packages/web/src/lib/shell/AuthenticatedShellBody.svelte:183`, :201), so that rejection is also unsurfaced. `busy=true` does not clear the shell or its session consumers. Local clearing and the server revocation lifecycle need independent handling so a stalled restore does not leave the person visibly signed in and lose the usable revocation credential. Pending sidebar network writes can extend the delay further because :441 has no whole-operation deadline. ## Restore-timeout UI follow-up The API wrapper does not automatically retry 503, so there is no immediate request-wrapper retry loop. The gate remains open while the actual reconciliation is pending, however. Dashboard polling runs every 2 seconds. Each tick increments the poller's generation before noticing its request is already in flight (:38–42). At the 10-second gate rejection, the saved request generation is stale, so :55 skips `onError`; :59 starts the queued follow-up, which enters the same gate again. Continued ticks repeat this behavior. A separate Bun diagnostic using unchanged compiled `api.ts` and `visible-poller.ts` observes two polling requests and zero `onError` calls after 12.1 seconds with a held gate and the actual 2-second interval. No fetch is dispatched. Dashboard's delayed announcement/error state is set only in `onError` (`packages/web/src/routes/+page.svelte:54`); initial/manual loading or a prior Live inventory indicator can therefore persist. This is source plus local timer evidence, not production-browser rendering evidence. When reconciliation eventually completes, ordinary retry can recover; indefinitely pending reconciliation requires sign-out/re-entry or reload. ## Round-1 regression checks and credentials The local fixture confirms that an intact advanced epoch ends a cached session before any HTTP dispatch; sign-out during peer wait cancels refresh without falling through; inventory dispatch waits for peer reconciliation and takes the successor; expired-account recovery does not recurse through the gate; server-rejection injection clears auth; and two restored documents using a serial lock and delayed peer messages produce one rotation and share the successor. No new credential persistence or logging was found. localStorage contains only the numeric generation and sign-out epoch. **BroadcastChannel session messages deliberately contain the access credential** in addition to those counters, as before these fixes and as specified in contracts §1.1. Session requests carry counters; sign-out messages carry only their type. No refresh credential is stored or broadcast by this auth code. The document-local boundary does not serialize the string `local`, publish an access credential, or answer peer session requests (`exchangeEpoch()` is null); its fresh shared HttpOnly cookie still affects later refreshes, which is why the failed-write P1 matters. Stream URLs use the separate stream ticket, not an access or refresh credential. ## Verification All Bun/Vitest execution used `nice -n 15`. The first Vitest attempt exited 127 because dependencies were absent. `bun install --frozen-lockfile` succeeded with no tracked changes, then the full web suite passed. Command: `nice -n 15 bun run --cwd packages/web test` ```text RUN v5.0.1 /mnt/hdd/infraternal/wt-lp/rereview2-port-auth/packages/web Test Files 13 passed (13) Tests 77 passed (77) Start at 11:44:12 Duration 3.63s (transform 58%, tests 32%, import 8%, worker 1%) ``` Exit status: 0. Full output: `vitest.log`. Command: `nice -n 15 bun /mnt/hdd/infraternal/jobs/rereview2-port-auth/check.mjs` ```text PASS prior missed-signout scenario: intact epoch clears before any HTTP dispatch. PASS prior peer-wait cancellation: no refresh dispatch after sign-out. PASS prior API barrier scenario: current peer credential used after reconciliation. PASS unreadable storage: no refresh dispatch or session adoption. PASS removed/lowered/invalid/noncanonical/unsafe epoch: frozen session ends before dispatch. PASS sign-out during completed reconciliation: revocation POST reaches dispatch bypass. PASS stalled reconciliation: abort rejects promptly; session clear releases other callers. PASS expired restore: account 401 recovers and retries without gate recursion. PASS server revocation: account and refresh rejection clear the session. PASS document-local passkey boundary: no credential messages; frozen session clears with and without Locks. PASS two restored documents: serial lock gives one rotation and shared successor. PASS timeout contract: API returns session_restoring 503, stream wait settles, late refresh cannot restore. OBSERVED sign-out limitation: local state waits 10 seconds; timed-out rotation sends held credential, server rejection surfaces. Local diagnostic checks completed; synthetic values only. OBSERVED epoch continuity gap: failed sign-out write leaves the readable boundary unchanged; cached document remains eligible to resume. ``` Exit status: 0. Source was compiled unchanged into external artifacts with Bun and the installed Svelte compiler. Prior diagnostics were adapted to assert fixed behavior and supply the accepted persisted epoch. All fixture credentials and ceremonies were synthetic; no real credentials were used or printed. Command: `nice -n 15 bun /mnt/hdd/infraternal/jobs/rereview2-port-auth/poller-check.mjs` ```text OBSERVED polling interaction: 10-second gate error is suppressed after 2-second poll ticks; second wait starts, onError remains uncalled. ``` Exit status: 0. These are diagnostic checks, not a scripts/verify gate. No Rust build, live-server test, production-browser smoke, actual WebAuthn/bfcache test, browser matrix or performance measurement was run under this Bun/Vitest-only scope. Required merge-gate approval remains with the verification job. Graph orientation used the prior round's external graph (auth, server sign-out, sidebar flush, polling and stream recovery nodes; `graph-orientation.txt`). A rebuild into this job's external graph directory was started because auth was stale, but stopped incomplete after slow filesystem traversal on the loaded VM; current auth evidence comes from the exact diff and source reads. No repo index/source was modified. Artifacts are contained in this job directory. Final git status is clean and HEAD is unchanged.
Author
Owner

Started defensive read-mostly review at detached calternal-port HEAD 76db215554. Bases: 1f08f14 and 38ddd3d. Scope: bfcache reload ordering, prior three review scenarios, live-tab coordination, web Vitest and external failure-injection artifacts. No commits or pushes.

Started defensive read-mostly review at detached calternal-port HEAD 76db2155548b1f1d831516dc1a9fde7f471108f2. Bases: 1f08f14 and 38ddd3d. Scope: bfcache reload ordering, prior three review scenarios, live-tab coordination, web Vitest and external failure-injection artifacts. No commits or pushes.
Author
Owner

Defensive review findings at 76db215554:

do not merge.

  • Major / P1, blocks merge — packages/web/src/lib/auth.svelte.ts:96 (also packages/web/src/lib/visible-poller.ts:81, packages/web/src/lib/api.ts:27): restored visibility dispatches authenticated inventory before persisted pageshow; requesting reload also leaves the old document executable until replacement, so the promised zero-request boundary is absent.
  • Major / P1, blocks merge — packages/web/src/lib/stream-attachment.svelte.ts:183 (also :175, :207): recovery already awaiting auth refresh at pagehide does not recheck suspension after the await and creates a fresh ticket/WebSocket from the suspended document.
  • Major / P1, blocks merge — packages/web/src/lib/auth.svelte.ts:197 (also :188, :135): live-tab sign-out during the peer wait falls through to performRefresh, which captures the new epoch and accepts the response, violating local-passkey-only re-entry.

Evidence: actual Chromium persisted restore dispatches unchanged inventory polling before pageshow; held stream recovery reconnects after pagehide; live peer-wait sign-out falls through to refresh. Full report: /mnt/hdd/infraternal/jobs/review-port-reload/findings.md. No tracked edits or commits.

Defensive review findings at 76db2155548b1f1d831516dc1a9fde7f471108f2: **do not merge**. - **Major / P1, blocks merge** — `packages/web/src/lib/auth.svelte.ts:96` (also `packages/web/src/lib/visible-poller.ts:81`, `packages/web/src/lib/api.ts:27`): restored visibility dispatches authenticated inventory before persisted pageshow; requesting reload also leaves the old document executable until replacement, so the promised zero-request boundary is absent. - **Major / P1, blocks merge** — `packages/web/src/lib/stream-attachment.svelte.ts:183` (also :175, :207): recovery already awaiting auth refresh at pagehide does not recheck suspension after the await and creates a fresh ticket/WebSocket from the suspended document. - **Major / P1, blocks merge** — `packages/web/src/lib/auth.svelte.ts:197` (also :188, :135): live-tab sign-out during the peer wait falls through to performRefresh, which captures the new epoch and accepts the response, violating local-passkey-only re-entry. Evidence: actual Chromium persisted restore dispatches unchanged inventory polling before pageshow; held stream recovery reconnects after pagehide; live peer-wait sign-out falls through to refresh. Full report: /mnt/hdd/infraternal/jobs/review-port-reload/findings.md. No tracked edits or commits.
Author
Owner

Finished defensive review. HEAD remains 76db215554 (detached calternal-port), compared with 1f08f14 and 38ddd3d. No tracked changes, commits or pushes. Verdict: do not merge; three Major/P1 findings recorded in findings.md and preceding issue comment.

Verification is diagnostic, not a scripts/verify merge gate. Default web Vitest run had 4 failures after two 5-second timeouts (vitest-first.log); single-worker extended-timeout full suite passed. Exact final output:

RUN  v5.0.1 /mnt/hdd/infraternal/wt-lp/review-port-reload/packages/web


 Test Files  13 passed (13)
      Tests  69 passed (69)
   Start at  12:08:16
   Duration  16.24s (transform 46%, tests 37%, import 15%, worker 1%)

nice -n 15 bun /mnt/hdd/infraternal/jobs/review-port-reload/check.mjs (exit 0):

CONFIRMED visibility poll dispatch before reload.
CONFIRMED visibility poll dispatch before reload with unavailable storage.
CONFIRMED later pageshow callback still dispatches after reload is requested; fallback mode installs reload listener.
CONFIRMED live-tab peer-wait sign-out falls through to refresh and accepts its response.
PASS ordinary sign-out dispatches server revocation directly and fences later refresh.
PASS sign-out during already-dispatched refresh discards the late response.
Local diagnostics completed with synthetic data only.

nice -n 15 bun /mnt/hdd/infraternal/jobs/review-port-reload/stream-check.mjs (exit 0):

CONFIRMED stream recovery awaiting auth refresh at pagehide creates a new ticket and WebSocket after suspension, despite pageSuspended remaining true.
Local stream diagnostic completed with real unchanged StreamClient code and synthetic transport responses.

nice -n 15 bun /mnt/hdd/infraternal/jobs/review-port-reload/browser-check.mjs (exit 0):

Chromium 153.0.8010.12
CONFIRMED actual bfcache: unchanged inventory poller dispatches /api/v1/hosts from restored document before persisted pageshow/reload listener.
PASS reload replaces the document once; fresh document navigation type is reload and pageshow is not persisted.

Full report and artifacts: /mnt/hdd/infraternal/jobs/review-port-reload/findings.md. No production-browser gate, Rust build or performance certification; merge verification remains outstanding.

Finished defensive review. HEAD remains 76db2155548b1f1d831516dc1a9fde7f471108f2 (detached calternal-port), compared with 1f08f14 and 38ddd3d. No tracked changes, commits or pushes. Verdict: do not merge; three Major/P1 findings recorded in findings.md and preceding issue comment. Verification is diagnostic, not a scripts/verify merge gate. Default web Vitest run had 4 failures after two 5-second timeouts (vitest-first.log); single-worker extended-timeout full suite passed. Exact final output: ```text RUN v5.0.1 /mnt/hdd/infraternal/wt-lp/review-port-reload/packages/web Test Files 13 passed (13) Tests 69 passed (69) Start at 12:08:16 Duration 16.24s (transform 46%, tests 37%, import 15%, worker 1%) ``` `nice -n 15 bun /mnt/hdd/infraternal/jobs/review-port-reload/check.mjs` (exit 0): ```text CONFIRMED visibility poll dispatch before reload. CONFIRMED visibility poll dispatch before reload with unavailable storage. CONFIRMED later pageshow callback still dispatches after reload is requested; fallback mode installs reload listener. CONFIRMED live-tab peer-wait sign-out falls through to refresh and accepts its response. PASS ordinary sign-out dispatches server revocation directly and fences later refresh. PASS sign-out during already-dispatched refresh discards the late response. Local diagnostics completed with synthetic data only. ``` `nice -n 15 bun /mnt/hdd/infraternal/jobs/review-port-reload/stream-check.mjs` (exit 0): ```text CONFIRMED stream recovery awaiting auth refresh at pagehide creates a new ticket and WebSocket after suspension, despite pageSuspended remaining true. Local stream diagnostic completed with real unchanged StreamClient code and synthetic transport responses. ``` `nice -n 15 bun /mnt/hdd/infraternal/jobs/review-port-reload/browser-check.mjs` (exit 0): ```text Chromium 153.0.8010.12 CONFIRMED actual bfcache: unchanged inventory poller dispatches /api/v1/hosts from restored document before persisted pageshow/reload listener. PASS reload replaces the document once; fresh document navigation type is reload and pageshow is not persisted. ``` Full report and artifacts: /mnt/hdd/infraternal/jobs/review-port-reload/findings.md. No production-browser gate, Rust build or performance certification; merge verification remains outstanding.
Author
Owner

Resume rs-port on branch calternal-port at base head 76db215554. Worktree is clean. The previous progress note identifies an intermittent browser assertion in checkLogControls (“Jump to latest” after ArrowUp); I’m checking the release build first, then will fix the remaining condition wait and run the browser/fast gates requested for this continuation. No push.

Resume rs-port on branch calternal-port at base head 76db2155548b1f1d831516dc1a9fde7f471108f2. Worktree is clean. The previous progress note identifies an intermittent browser assertion in checkLogControls (“Jump to latest” after ArrowUp); I’m checking the release build first, then will fix the remaining condition wait and run the browser/fast gates requested for this continuation. No push.
Author
Owner

Resuming rs-session-authority as the only writer in /mnt/hdd/infraternal/wt-lp/session-authority, branch session-authority, base/resume head cd7ca3faf07621804f642f8e0f1793f72024e637. Worktree is clean. The existing commit contains A3/A5/A8/A10/A11 implementation and regressions; I am recovering the prior workspace-test failure, rerunning it in isolation before changing code, and finishing with the requested INFRATERNAL_VERIFY_RUN_ID=rs-session-authority scripts/verify fast. Lean Cargo environment, two build workers, nice 15, root-disk target cache. No merge gate or push.

Resuming rs-session-authority as the only writer in `/mnt/hdd/infraternal/wt-lp/session-authority`, branch `session-authority`, base/resume head `cd7ca3faf07621804f642f8e0f1793f72024e637`. Worktree is clean. The existing commit contains A3/A5/A8/A10/A11 implementation and regressions; I am recovering the prior workspace-test failure, rerunning it in isolation before changing code, and finishing with the requested `INFRATERNAL_VERIFY_RUN_ID=rs-session-authority scripts/verify fast`. Lean Cargo environment, two build workers, nice 15, root-disk target cache. No merge gate or push.
Author
Owner

Resuming rs-mutation-safety directly in worktree /mnt/hdd/infraternal/wt-lp/mutation-safety, branch mutation-safety. Base head: 450c297; current head: 1f629548fa69d0b51443ea6f3b01656ad74b59a5. Worktree is clean. Existing implementation for D1/D2/D7/D10/D15 is committed. Checking prior test evidence, then rerunning isolated failures and the requested INFRATERNAL_VERIFY_RUN_ID=rs-mutation-safety scripts/verify fast under the lean build environment. No push or merge gate. A6 only if it fits the current provider seam cheaply.

Resuming rs-mutation-safety directly in worktree /mnt/hdd/infraternal/wt-lp/mutation-safety, branch mutation-safety. Base head: 450c297; current head: 1f629548fa69d0b51443ea6f3b01656ad74b59a5. Worktree is clean. Existing implementation for D1/D2/D7/D10/D15 is committed. Checking prior test evidence, then rerunning isolated failures and the requested INFRATERNAL_VERIFY_RUN_ID=rs-mutation-safety scripts/verify fast under the lean build environment. No push or merge gate. A6 only if it fits the current provider seam cheaply.
Author
Owner

Resuming rs-stream-conformance as sole writer on branch stream-conformance. Base 450c297; starting HEAD ff65f249a1a6c72e4c5dc995f230dfdf23e53826, clean worktree. Checking prior conformance work and remaining documentation/tests; lean root-disk Cargo cache, nice 15, two build jobs. Final requested gate is INFRATERNAL_VERIFY_RUN_ID=rs-stream-conformance scripts/verify fast; no merge gate or push.

Resuming rs-stream-conformance as sole writer on branch `stream-conformance`. Base `450c297`; starting HEAD `ff65f249a1a6c72e4c5dc995f230dfdf23e53826`, clean worktree. Checking prior conformance work and remaining documentation/tests; lean root-disk Cargo cache, nice 15, two build jobs. Final requested gate is `INFRATERNAL_VERIFY_RUN_ID=rs-stream-conformance scripts/verify fast`; no merge gate or push.
Author
Owner

Browser-check inspection at 76db215 found 50 route navigations, 3 reloads and 1 post-navigation wait using networkidle; the Terminals route polls sessions every 3 seconds. These now wait for the signed-in #route-content or .auth-screen, followed by each flow's existing route-specific condition. The Playwright fixed-wait calls are removed: log pause waits for an incoming DATA frame and unchanged record count, Jump to latest waits for end position after the next record, and stream lifecycle instrumentation flags DATA after CLOSE. The two-tab refresh test now observes the queued infraternal-refresh lock via LockManager.query() before releasing the held response. The terminal reattach check holds ticket responses until it verifies the terminal has not taken focus, then releases them and verifies attached focus. No browser gate has run yet.

Browser-check inspection at 76db215 found 50 route navigations, 3 reloads and 1 post-navigation wait using `networkidle`; the Terminals route polls sessions every 3 seconds. These now wait for the signed-in `#route-content` or `.auth-screen`, followed by each flow's existing route-specific condition. The Playwright fixed-wait calls are removed: log pause waits for an incoming DATA frame and unchanged record count, Jump to latest waits for end position after the next record, and stream lifecycle instrumentation flags DATA after CLOSE. The two-tab refresh test now observes the queued `infraternal-refresh` lock via [`LockManager.query()`](https://www.w3.org/TR/web-locks/) before releasing the held response. The terminal reattach check holds ticket responses until it verifies the terminal has not taken focus, then releases them and verifies attached focus. No browser gate has run yet.
Author
Owner

Verification is blocked by the build environment at unchanged head cd7ca3faf07621804f642f8e0f1793f72024e637.

The preset root-cache path was redirected to the worktree's HDD target during this job. The fast gate then failed at Clippy with SQLx/either artifact hash mismatch E0460. A separate root-disk cache copy was started to preserve the existing target and retry without HDD builds, but concurrent disk use reduced root free space from 19 GiB to 6.5 GiB and then 3.6 GiB. I stopped only my copy to avoid filling the root filesystem. The copied partial cache is /home/kayg/.cache/infraternal-targets/rs-session-authority-resume. No other job was signalled and no source was changed.

The fresh full workspace test run before the gate passed (exit 0); the earlier cargo-test failure did not reproduce. Product-source fixes are already committed at the head above. Fast remains incomplete, not green. Requested orchestration help to free root space or provide a permitted cache location; root-disk cache constraint prevents falling back to HDD builds.

Verification is blocked by the build environment at unchanged head `cd7ca3faf07621804f642f8e0f1793f72024e637`. The preset root-cache path was redirected to the worktree's HDD target during this job. The fast gate then failed at Clippy with SQLx/`either` artifact hash mismatch E0460. A separate root-disk cache copy was started to preserve the existing target and retry without HDD builds, but concurrent disk use reduced root free space from 19 GiB to 6.5 GiB and then 3.6 GiB. I stopped only my copy to avoid filling the root filesystem. The copied partial cache is `/home/kayg/.cache/infraternal-targets/rs-session-authority-resume`. No other job was signalled and no source was changed. The fresh full workspace test run before the gate passed (exit 0); the earlier cargo-test failure did not reproduce. Product-source fixes are already committed at the head above. Fast remains incomplete, not green. Requested orchestration help to free root space or provide a permitted cache location; root-disk cache constraint prevents falling back to HDD builds.
Author
Owner

rs-stream-conformance finished on branch stream-conformance, HEAD 6e687f50d6cc70a4c8e7543bf9ff0b107b56c4bb, base 450c297. No push or merge; issues remain open.

Preserved prior commit ff65f24 implementing D3/D4/D5/D6/D17: stream/tunnel oversize close 1009; channel-local invalid RESIZE; bounded tunnel frames, close codes, per-channel OPEN_ERR refusals, timestamped PING and shared control admission; generated TypeScript OPEN_ERR validation for all registered errors; cumulative Rust control budget shared by CLI and SSH clients.

Resume commits:

  • 9d4e23b: discard invalid RESIZE after channel retirement. A real TCP WebSocket regression verifies OPEN_ERR followed by late RESIZE produces PONG without a second CLOSE.
  • 6e687f5: document the Rust sliding one-second 256 KiB admission limit and tunnel inventory exception; add steady-state CREDIT and cumulative-refusal benchmarks to the existing proto harness; reject excessive payload counts without arithmetic overflow, with a regression test. Deque capacity reuse and bounded growth are explained in code.

All checks below completed with exit 0. Rust commands used CARGO_INCREMENTAL=0, CARGO_PROFILE_DEV_DEBUG=0, CARGO_PROFILE_TEST_DEBUG=0, CARGO_BUILD_JOBS=2, the preset root-disk CARGO_TARGET_DIR and nice -n 15. No timing failures required isolation or a retry. No verify merge was run. The final fast gate covers the committed source; its Rust tests include real TCP and mTLS conformance tests. Docker/Podman/sshd integration tiers and perf-test-VM A/B are not certified by this fast run. Criterion ran in test mode only; no performance measurements are claimed.

Requested gate: INFRATERNAL_VERIFY_RUN_ID=rs-stream-conformance scripts/verify fast (exit 0), output verbatim:

WARN load5=37.83 exceeds online CPU count=8; timing-sensitive checks may be delayed
PASS fast: migrations are append-only (0.659s)
PASS fast: workspace package dependencies (13.237s)
PASS fast: JavaScript dependencies (5.596s)
PASS fast: advisory review policy tests (0.140s)
SUPPLY_CHAIN_REVIEWS advisory exceptions are within their review windows
SUPPLY_CHAIN cargo-deny: cargo-deny 0.20.2
SUPPLY_CHAIN_NOTICES generated THIRD_PARTY_NOTICES.md from 95 frontend packages
SUPPLY_CHAIN_NOTICES copied source: 179 shadcn files, 3 calternal-derived files
SUPPLY_CHAIN_NOTICES license files: 66 distinct texts; 0 packages need manual license review
advisories ok
SUPPLY_CHAIN_RUST_ADVISORIES passed with refreshed advisory data
licenses ok
SUPPLY_CHAIN_RUST_LICENSES passed
bun audit v1.4.2 (744846f84)

cookie@0.6.0
  workspace:@infraternal/web > @sveltejs/kit > cookie
  low: cookie accepts cookie name, path, and domain with out of bounds characters (<0.7.0) - https://github.com/advisories/GHSA-pxg6-pf52-xh8x

1 vulnerability (1 low)

  bun audit fix           upgrade the vulnerable packages within their ranges
  bun audit fix --latest  also cross major versions
SUPPLY_CHAIN_BUN_AUDIT findings reported; this check is report-only
SUPPLY_CHAIN_PASS Rust advisory/license checks complete; Bun findings are report-only
PASS fast: supply-chain checks (48.624s)
PASS fast: build web app (75.997s)
PASS fast: cargo fmt --check (2.893s)
PASS fast: cargo clippy (1262.559s)
PASS fast: cargo test (940.319s)
PASS fast: svelte-check (133.779s)
PASS fast: UI package svelte-check (42.354s)
PASS fast: stream package typecheck (20.098s)
PASS fast: Vitest (19.321s)
PASS fast: UI package Vitest (63.849s)
PASS fast: stream package Vitest (2.178s)
PASS fast: OpenAPI and TypeScript client drift (143.634s)
PASS fast: terminal TypeScript (6.588s)
PASS fast: terminal Vitest (1.907s)

Workspace Rust test results and selected conformance test lines, verbatim:

test stream::tests::control_frame_flood_closes_websocket_with_policy_code_1008 ... ok
test stream::tests::oversized_frame_closes_websocket_with_message_too_big_code_1009 ... ok
test result: ok. 48 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.04s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.22s
test result: ok. 8 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 0 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.53s
test remote::tests::benchmark_tunnel_credit_accounting ... ignored, benchmark only on the perf-test VM
test remote::tests::live_tunnel_reconciliation_preserves_unrelated_channel ... ignored, requires real Docker and rootless Podman
test remote::tests::bulk_channel_completion_stays_behind_its_queued_data ... ok
test remote::tests::enrollment_origin_only_allows_loopback_http_or_https_root ... ok
test remote::tests::excess_or_malformed_open_is_refused_without_ending_the_tunnel ... ok
test remote::tests::forced_authorization_close_overtakes_queued_bulk_data ... ok
test remote::tests::frames_for_retired_ids_are_discarded_and_never_opened_ids_are_fatal ... ok
test remote::tests::inbound_websocket_messages_map_to_contract_close_codes ... ok
test remote::tests::physical_tunnel_credit_is_shared_across_clients_and_released ... ok
test remote::tests::private_identity_files_are_owner_only_and_not_overwritten ... ok
test remote::tests::tunnel_ping_carries_the_current_unix_time ... ok
test remote::tests::tunnel_websocket_limits_are_one_contract_frame ... ok
test remote::tests::tunnel_writer_sends_the_requested_close_code ... ok
test result: ok. 17 passed; 0 failed; 7 ignored; 0 measured; 0 filtered out; finished in 0.21s
test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.29s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test docker_exec_pty_reports_initial_and_resized_dimensions_to_child ... ignored, requires rootful Docker
test result: ok. 0 passed; 0 failed; 12 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test stream::bucket::tests::empty_payloads_only_spend_frame_tokens ... ok
test stream::bucket::tests::excessive_payload_is_refused_without_overflow_or_spending_admission ... ok
test stream::bucket::tests::frame_rate_has_a_burst_then_refills_at_200_per_second ... ok
test stream::bucket::tests::payload_budget_is_cumulative_across_frames_not_per_frame ... ok
test stream::frame::tests::resize_direction_depends_on_the_connection_peer ... ok
test result: ok. 66 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.11s
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.74s
test tests::console_does_not_imply_exec_and_resize_requires_pty ... ok
test result: ok. 25 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.23s
test capabilities::tests::termination_ack_deadline_includes_a_stalled_resize_lock ... ignored, run explicitly; injects a stalled resize lock
test result: ok. 47 passed; 0 failed; 5 ignored; 0 measured; 0 filtered out; finished in 3.10s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 0 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 0.00s
test stream::tests::out_of_range_resize_closes_only_its_channel_with_invalid_value ... ok
test result: ok. 109 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 9.51s
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.82s
test tunnel_violations_close_with_contract_codes_and_agent_open_is_refused ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.48s
test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 16.27s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.81s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.82s
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.41s
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.99s
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 57.57s
test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s
test host_trust_stream_replay_resize_close_and_changed_key ... ignored, requires real sshd, ssh-keygen and tmux
test result: ok. 0 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.57s
test oversized_client_message_is_refused_with_close_1009 ... ok
test out_of_range_resize_for_a_retired_channel_is_discarded ... ok
test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.62s
test result: ok. 9 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 0.28s
test result: ok. 7 passed; 0 failed; 12 ignored; 0 measured; 0 filtered out; finished in 11.75s
test result: ok. 34 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.76s
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
test pty_resize_and_replay ... ignored, requires OpenSSH server tools (sshd and ssh-keygen)
test result: ok. 1 passed; 0 failed; 15 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 1 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 0.14s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Focused stream package: bun --cwd=packages/stream run check and bun --cwd=packages/stream run test, both nice -n 15, exit 0; output verbatim:

$ tsc --noEmit
$ vitest run

 RUN  v5.0.1 /mnt/hdd/infraternal/wt-lp/stream-conformance/packages/stream


 Test Files  4 passed (4)
      Tests  75 passed (75)
   Start at  12:36:27
   Duration  7.68s (transform 51%, tests 30%, import 13%, worker 6%)

  Transform  transforming modules took 6.89s · 51% of tracked time, re-done on every run
             persist transforms across runs with fsModuleCache: true
             learn more: https://vitest.dev/guide/improving-performance#caching-between-reruns

Benchmark smoke: cargo test -p infraternal-proto --bench stream -- control_admission --test, exit 0; output verbatim:

   Compiling syn v2.0.119
   Compiling serde_core v1.0.229
   Compiling syn v3.0.6
   Compiling zerocopy-derive v0.8.59
   Compiling serde v1.0.229
   Compiling getrandom v0.4.3
   Compiling serde_derive v1.0.229
   Compiling zerocopy v0.8.59
   Compiling serde_json v1.0.151
   Compiling memchr v2.8.3
   Compiling num-traits v0.2.19
   Compiling getrandom v0.3.4
   Compiling rustix v1.1.5
   Compiling cc v1.5.1
   Compiling rand_core v0.9.5
   Compiling linux-raw-sys v0.12.1
   Compiling either v1.18.0
   Compiling alloca v0.4.0
   Compiling chacha20 v0.10.2
   Compiling half v2.7.1
   Compiling once_cell v1.21.4
   Compiling indexmap v2.14.2
   Compiling ciborium-ll v0.2.2
   Compiling tempfile v3.27.0
   Compiling clap_builder v4.6.7
   Compiling rand v0.10.3
   Compiling itertools v0.13.0
   Compiling regex-automata v0.4.18
   Compiling ppv-lite86 v0.2.21
   Compiling utoipa-gen v5.5.0
   Compiling wait-timeout v0.2.1
   Compiling serde_json_canonicalizer v0.3.2
   Compiling rusty-fork v0.3.1
   Compiling tokio v1.53.1
   Compiling criterion-plot v0.8.2
   Compiling rand_chacha v0.9.0
   Compiling regex v1.13.1
   Compiling clap v4.6.7
   Compiling rayon v1.12.0
   Compiling utoipa v5.5.0
   Compiling ulid v3.0.0
   Compiling ciborium v0.2.2
   Compiling plotters v0.3.7
   Compiling tinytemplate v1.2.1
   Compiling rand v0.9.5
   Compiling rand_xorshift v0.4.0
   Compiling page_size v0.6.0
   Compiling infraternal-proto v0.0.1 (/mnt/hdd/infraternal/wt-lp/stream-conformance/crates/proto)
   Compiling criterion v0.8.2
   Compiling proptest v1.11.0
    Finished `test` profile [unoptimized] target(s) in 1m 22s
     Running benches/stream.rs (/home/kayg/.cache/infraternal-targets/rs-stream-conformance/debug/deps/stream-86dba6da9bb1aa28)
Gnuplot not found, using plotters backend
Testing control_admission_credit_steady_state
Success

Testing control_admission_cumulative_payload_refusal
Success

Code index rebuilt, refreshed after edits, and queried for ControlBucket and the stream impact radius. No independent review is claimed by this author job.

API references checked: Criterion batched reference timing, Criterion test mode, VecDeque capacity.

Final /usr/bin/git status --short output was empty (exit 0); temporary target symlink removed. Build artifacts and this report remain only in the root-disk cache.

rs-stream-conformance finished on branch `stream-conformance`, HEAD `6e687f50d6cc70a4c8e7543bf9ff0b107b56c4bb`, base `450c297`. No push or merge; issues remain open. Preserved prior commit `ff65f24` implementing D3/D4/D5/D6/D17: stream/tunnel oversize close 1009; channel-local invalid RESIZE; bounded tunnel frames, close codes, per-channel OPEN_ERR refusals, timestamped PING and shared control admission; generated TypeScript OPEN_ERR validation for all registered errors; cumulative Rust control budget shared by CLI and SSH clients. Resume commits: - `9d4e23b`: discard invalid RESIZE after channel retirement. A real TCP WebSocket regression verifies OPEN_ERR followed by late RESIZE produces PONG without a second CLOSE. - `6e687f5`: document the Rust sliding one-second 256 KiB admission limit and tunnel inventory exception; add steady-state CREDIT and cumulative-refusal benchmarks to the existing proto harness; reject excessive payload counts without arithmetic overflow, with a regression test. Deque capacity reuse and bounded growth are explained in code. All checks below completed with exit 0. Rust commands used CARGO_INCREMENTAL=0, CARGO_PROFILE_DEV_DEBUG=0, CARGO_PROFILE_TEST_DEBUG=0, CARGO_BUILD_JOBS=2, the preset root-disk CARGO_TARGET_DIR and nice -n 15. No timing failures required isolation or a retry. No `verify merge` was run. The final fast gate covers the committed source; its Rust tests include real TCP and mTLS conformance tests. Docker/Podman/sshd integration tiers and perf-test-VM A/B are not certified by this fast run. Criterion ran in test mode only; no performance measurements are claimed. Requested gate: `INFRATERNAL_VERIFY_RUN_ID=rs-stream-conformance scripts/verify fast` (exit 0), output verbatim: ```text WARN load5=37.83 exceeds online CPU count=8; timing-sensitive checks may be delayed PASS fast: migrations are append-only (0.659s) PASS fast: workspace package dependencies (13.237s) PASS fast: JavaScript dependencies (5.596s) PASS fast: advisory review policy tests (0.140s) SUPPLY_CHAIN_REVIEWS advisory exceptions are within their review windows SUPPLY_CHAIN cargo-deny: cargo-deny 0.20.2 SUPPLY_CHAIN_NOTICES generated THIRD_PARTY_NOTICES.md from 95 frontend packages SUPPLY_CHAIN_NOTICES copied source: 179 shadcn files, 3 calternal-derived files SUPPLY_CHAIN_NOTICES license files: 66 distinct texts; 0 packages need manual license review advisories ok SUPPLY_CHAIN_RUST_ADVISORIES passed with refreshed advisory data licenses ok SUPPLY_CHAIN_RUST_LICENSES passed bun audit v1.4.2 (744846f84) cookie@0.6.0 workspace:@infraternal/web > @sveltejs/kit > cookie low: cookie accepts cookie name, path, and domain with out of bounds characters (<0.7.0) - https://github.com/advisories/GHSA-pxg6-pf52-xh8x 1 vulnerability (1 low) bun audit fix upgrade the vulnerable packages within their ranges bun audit fix --latest also cross major versions SUPPLY_CHAIN_BUN_AUDIT findings reported; this check is report-only SUPPLY_CHAIN_PASS Rust advisory/license checks complete; Bun findings are report-only PASS fast: supply-chain checks (48.624s) PASS fast: build web app (75.997s) PASS fast: cargo fmt --check (2.893s) PASS fast: cargo clippy (1262.559s) PASS fast: cargo test (940.319s) PASS fast: svelte-check (133.779s) PASS fast: UI package svelte-check (42.354s) PASS fast: stream package typecheck (20.098s) PASS fast: Vitest (19.321s) PASS fast: UI package Vitest (63.849s) PASS fast: stream package Vitest (2.178s) PASS fast: OpenAPI and TypeScript client drift (143.634s) PASS fast: terminal TypeScript (6.588s) PASS fast: terminal Vitest (1.907s) ``` Workspace Rust test results and selected conformance test lines, verbatim: ```text test stream::tests::control_frame_flood_closes_websocket_with_policy_code_1008 ... ok test stream::tests::oversized_frame_closes_websocket_with_message_too_big_code_1009 ... ok test result: ok. 48 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.04s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.22s test result: ok. 8 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 0 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.53s test remote::tests::benchmark_tunnel_credit_accounting ... ignored, benchmark only on the perf-test VM test remote::tests::live_tunnel_reconciliation_preserves_unrelated_channel ... ignored, requires real Docker and rootless Podman test remote::tests::bulk_channel_completion_stays_behind_its_queued_data ... ok test remote::tests::enrollment_origin_only_allows_loopback_http_or_https_root ... ok test remote::tests::excess_or_malformed_open_is_refused_without_ending_the_tunnel ... ok test remote::tests::forced_authorization_close_overtakes_queued_bulk_data ... ok test remote::tests::frames_for_retired_ids_are_discarded_and_never_opened_ids_are_fatal ... ok test remote::tests::inbound_websocket_messages_map_to_contract_close_codes ... ok test remote::tests::physical_tunnel_credit_is_shared_across_clients_and_released ... ok test remote::tests::private_identity_files_are_owner_only_and_not_overwritten ... ok test remote::tests::tunnel_ping_carries_the_current_unix_time ... ok test remote::tests::tunnel_websocket_limits_are_one_contract_frame ... ok test remote::tests::tunnel_writer_sends_the_requested_close_code ... ok test result: ok. 17 passed; 0 failed; 7 ignored; 0 measured; 0 filtered out; finished in 0.21s test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.29s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test docker_exec_pty_reports_initial_and_resized_dimensions_to_child ... ignored, requires rootful Docker test result: ok. 0 passed; 0 failed; 12 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test stream::bucket::tests::empty_payloads_only_spend_frame_tokens ... ok test stream::bucket::tests::excessive_payload_is_refused_without_overflow_or_spending_admission ... ok test stream::bucket::tests::frame_rate_has_a_burst_then_refills_at_200_per_second ... ok test stream::bucket::tests::payload_budget_is_cumulative_across_frames_not_per_frame ... ok test stream::frame::tests::resize_direction_depends_on_the_connection_peer ... ok test result: ok. 66 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.11s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.74s test tests::console_does_not_imply_exec_and_resize_requires_pty ... ok test result: ok. 25 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.23s test capabilities::tests::termination_ack_deadline_includes_a_stalled_resize_lock ... ignored, run explicitly; injects a stalled resize lock test result: ok. 47 passed; 0 failed; 5 ignored; 0 measured; 0 filtered out; finished in 3.10s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 0 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 0.00s test stream::tests::out_of_range_resize_closes_only_its_channel_with_invalid_value ... ok test result: ok. 109 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 9.51s test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.82s test tunnel_violations_close_with_contract_codes_and_agent_open_is_refused ... ok test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.48s test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 16.27s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.81s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.82s test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.41s test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.99s test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 57.57s test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s test host_trust_stream_replay_resize_close_and_changed_key ... ignored, requires real sshd, ssh-keygen and tmux test result: ok. 0 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.57s test oversized_client_message_is_refused_with_close_1009 ... ok test out_of_range_resize_for_a_retired_channel_is_discarded ... ok test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.62s test result: ok. 9 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 0.28s test result: ok. 7 passed; 0 failed; 12 ignored; 0 measured; 0 filtered out; finished in 11.75s test result: ok. 34 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.76s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s test pty_resize_and_replay ... ignored, requires OpenSSH server tools (sshd and ssh-keygen) test result: ok. 1 passed; 0 failed; 15 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 1 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 0.14s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` Focused stream package: `bun --cwd=packages/stream run check` and `bun --cwd=packages/stream run test`, both nice -n 15, exit 0; output verbatim: ```text $ tsc --noEmit $ vitest run RUN v5.0.1 /mnt/hdd/infraternal/wt-lp/stream-conformance/packages/stream Test Files 4 passed (4) Tests 75 passed (75) Start at 12:36:27 Duration 7.68s (transform 51%, tests 30%, import 13%, worker 6%) Transform transforming modules took 6.89s · 51% of tracked time, re-done on every run persist transforms across runs with fsModuleCache: true learn more: https://vitest.dev/guide/improving-performance#caching-between-reruns ``` Benchmark smoke: `cargo test -p infraternal-proto --bench stream -- control_admission --test`, exit 0; output verbatim: ```text Compiling syn v2.0.119 Compiling serde_core v1.0.229 Compiling syn v3.0.6 Compiling zerocopy-derive v0.8.59 Compiling serde v1.0.229 Compiling getrandom v0.4.3 Compiling serde_derive v1.0.229 Compiling zerocopy v0.8.59 Compiling serde_json v1.0.151 Compiling memchr v2.8.3 Compiling num-traits v0.2.19 Compiling getrandom v0.3.4 Compiling rustix v1.1.5 Compiling cc v1.5.1 Compiling rand_core v0.9.5 Compiling linux-raw-sys v0.12.1 Compiling either v1.18.0 Compiling alloca v0.4.0 Compiling chacha20 v0.10.2 Compiling half v2.7.1 Compiling once_cell v1.21.4 Compiling indexmap v2.14.2 Compiling ciborium-ll v0.2.2 Compiling tempfile v3.27.0 Compiling clap_builder v4.6.7 Compiling rand v0.10.3 Compiling itertools v0.13.0 Compiling regex-automata v0.4.18 Compiling ppv-lite86 v0.2.21 Compiling utoipa-gen v5.5.0 Compiling wait-timeout v0.2.1 Compiling serde_json_canonicalizer v0.3.2 Compiling rusty-fork v0.3.1 Compiling tokio v1.53.1 Compiling criterion-plot v0.8.2 Compiling rand_chacha v0.9.0 Compiling regex v1.13.1 Compiling clap v4.6.7 Compiling rayon v1.12.0 Compiling utoipa v5.5.0 Compiling ulid v3.0.0 Compiling ciborium v0.2.2 Compiling plotters v0.3.7 Compiling tinytemplate v1.2.1 Compiling rand v0.9.5 Compiling rand_xorshift v0.4.0 Compiling page_size v0.6.0 Compiling infraternal-proto v0.0.1 (/mnt/hdd/infraternal/wt-lp/stream-conformance/crates/proto) Compiling criterion v0.8.2 Compiling proptest v1.11.0 Finished `test` profile [unoptimized] target(s) in 1m 22s Running benches/stream.rs (/home/kayg/.cache/infraternal-targets/rs-stream-conformance/debug/deps/stream-86dba6da9bb1aa28) Gnuplot not found, using plotters backend Testing control_admission_credit_steady_state Success Testing control_admission_cumulative_payload_refusal Success ``` Code index rebuilt, refreshed after edits, and queried for ControlBucket and the stream impact radius. No independent review is claimed by this author job. API references checked: [Criterion batched reference timing](https://docs.rs/criterion/latest/criterion/struct.Bencher.html#method.iter_batched_ref), [Criterion test mode](https://bheisler.github.io/criterion.rs/book/faq.html), [VecDeque capacity](https://doc.rust-lang.org/std/collections/struct.VecDeque.html). Final `/usr/bin/git status --short` output was empty (exit 0); temporary target symlink removed. Build artifacts and this report remain only in the root-disk cache.
Author
Owner

rs-tunnel-drop completed at HEAD 2abb7e93d66bcde5015dbc9a9d45223f754c609b on tunnel-drop-close; merged batch-1003a including 22ac67d and retained original stop deadlines. Drop/replacement now use the audited host_offline path, with local-channel isolation and generation-preservation regressions. Required final INFRATERNAL_VERIFY_RUN_ID=rs-tunnel-drop scripts/verify fast exited 0; no merge gate or push. Full head, findings and verbatim gate/focused test output are recorded in #49. Two prior focused inherited rate-limit flood failures are recorded there; final workspace tests passed.

rs-tunnel-drop completed at HEAD `2abb7e93d66bcde5015dbc9a9d45223f754c609b` on `tunnel-drop-close`; merged batch-1003a including 22ac67d and retained original stop deadlines. Drop/replacement now use the audited host_offline path, with local-channel isolation and generation-preservation regressions. Required final `INFRATERNAL_VERIFY_RUN_ID=rs-tunnel-drop scripts/verify fast` exited 0; no merge gate or push. Full head, findings and verbatim gate/focused test output are recorded in [#49](https://git.kayg.org/kayg/infraternal/issues/49). Two prior focused inherited rate-limit flood failures are recorded there; final workspace tests passed.
Author
Owner

rs-replay-admission resume finished on replay-book-admission.

Head: dbb19e7b51e9c5acf6c2312cf25071f1eb9da70c. Resume base: 9dd7fa5d1f565fc7f08e77b6869432607a5a0042. New logical commit: fix(authz): isolate plan grants from read replay admission. Worktree is clean; no push and no issues closed. Related: #49 / #48 / #46.

Finished the remaining scope:

  • Preserved the previous A1/A9 implementation: every pre-action and post-action signed inspect is admitted, embedded routing included; budgets use users rather than tokens, with an owner-wide ceiling. Refused read-only action requests sign nothing.
  • Completed the explicit A2 requirement for plans on their own book: three independently bounded 4096-entry replay books for reads, plans and OPEN/actions. The server and infraternal agent share the classification, and plan grants use separate per-(user, owning infraternal agent) admission buckets, at the read numeric rates. Legacy OPEN and provider grants retain the 10 s server lifetime.
  • Retained A7's atomic fence/idempotency mark and the 130 s execution deadline. Corrected the freshness documentation: signing follows the fence commit, so the 10 s lifetime bounds acceptance from signing; a scheduling delay before signing is outside that bound.
  • Added fixed-time full-book isolation checks in both directions, OPEN/action acceptance with full read/plan books, and plan-book clearing/old-nonce denial after tunnel reset. Admission tests now exercise all three classes at a controlled instant. Added the perf-VM-only warm acceptance/refusal benchmark; no performance measurement or budget certification is claimed.

Regression proof: before the split, the test failed with a full read book must leave plan grants available: ResourceExhausted (exit 101). Final workspace tests include the strengthened fixed-time and nonce-reset checks. Relevant final test output, quoted verbatim:

test unsupported_tampered_stale_binding_and_malformed_calls_fail_before_provider_io ... ok
test discovery_inspect_plan_and_action_round_trip_through_the_runtime ... ok
test read_flood_cannot_starve_open_or_mutation_grants ... ok
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 83.15s
test host_route::tests::admission_ceilings_stay_below_replay_book_capacity ... ok
test host_route::tests::admission_is_per_user_and_agent_with_an_agent_ceiling ... ok
test host_route::tests::benchmark_grant_admission ... ignored, benchmark only on the perf-test VM; A/B against the base head
test storage::fence_tests::container_dispatch_marks_idempotency_inside_the_fence ... ok
test tunnel::provider_rpc_tests::read_only_action_flood_signs_nothing_and_leaves_the_owner_working ... ok
test result: ok. 114 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 8.45s

Required gate command: nice -n 15 env CARGO_INCREMENTAL=0 CARGO_PROFILE_DEV_DEBUG=0 CARGO_PROFILE_TEST_DEBUG=0 CARGO_BUILD_JOBS=2 INFRATERNAL_VERIFY_RUN_ID=rs-replay-admission scripts/verify fast. Exit 0. Exact complete gate output:

WARN load5=37.26 exceeds online CPU count=8; timing-sensitive checks may be delayed
PASS fast: migrations are append-only (2.056s)
PASS fast: workspace package dependencies (3.350s)
PASS fast: JavaScript dependencies (0.534s)
PASS fast: advisory review policy tests (1.458s)
SUPPLY_CHAIN_REVIEWS advisory exceptions are within their review windows
SUPPLY_CHAIN cargo-deny: cargo-deny 0.20.2
SUPPLY_CHAIN_NOTICES generated THIRD_PARTY_NOTICES.md from 95 frontend packages
SUPPLY_CHAIN_NOTICES copied source: 179 shadcn files, 3 calternal-derived files
SUPPLY_CHAIN_NOTICES license files: 66 distinct texts; 0 packages need manual license review
advisories ok
SUPPLY_CHAIN_RUST_ADVISORIES passed with refreshed advisory data
licenses ok
SUPPLY_CHAIN_RUST_LICENSES passed
bun audit v1.4.2 (744846f84)

cookie@0.6.0
  workspace:@infraternal/web > @sveltejs/kit > cookie
  low: cookie accepts cookie name, path, and domain with out of bounds characters (<0.7.0) - https://github.com/advisories/GHSA-pxg6-pf52-xh8x

1 vulnerability (1 low)

  bun audit fix           upgrade the vulnerable packages within their ranges
  bun audit fix --latest  also cross major versions
SUPPLY_CHAIN_BUN_AUDIT findings reported; this check is report-only
SUPPLY_CHAIN_PASS Rust advisory/license checks complete; Bun findings are report-only
PASS fast: supply-chain checks (41.606s)
PASS fast: build web app (109.051s)
PASS fast: cargo fmt --check (5.661s)
PASS fast: cargo clippy (996.863s)
PASS fast: cargo test (558.788s)
PASS fast: svelte-check (49.863s)
PASS fast: UI package svelte-check (10.158s)
PASS fast: stream package typecheck (15.425s)
PASS fast: Vitest (16.905s)
PASS fast: UI package Vitest (62.335s)
PASS fast: stream package Vitest (3.315s)
PASS fast: OpenAPI and TypeScript client drift (188.201s)
PASS fast: terminal TypeScript (7.974s)
PASS fast: terminal Vitest (2.652s)

The low cookie advisory is the existing report-only Bun finding. No dependency changes. No verify merge, other full gate, or perf-VM A/B was run; independent review and merge/performance gates remain with the orchestrator.

Tooling/host notes: the graph was absent; rebuild and queries were attempted before raw searches, but queries returned no indexed nodes while the database was locked. The owned prolonged rebuild was stopped and direct source/diff review supplied the fallback. The preset root-disk cache was cold. The former worktree target was moved off /mnt/hdd; its obsolete cache was later removed when root free space fell to 8 GB. A temporary root-target symlink supported the gate summary and was removed after the gate. Active build artifacts remain only in the preset root-disk target, outside git.

rs-replay-admission resume finished on `replay-book-admission`. Head: `dbb19e7b51e9c5acf6c2312cf25071f1eb9da70c`. Resume base: `9dd7fa5d1f565fc7f08e77b6869432607a5a0042`. New logical commit: `fix(authz): isolate plan grants from read replay admission`. Worktree is clean; no push and no issues closed. Related: #49 / #48 / #46. Finished the remaining scope: - Preserved the previous A1/A9 implementation: every pre-action and post-action signed inspect is admitted, embedded routing included; budgets use users rather than tokens, with an owner-wide ceiling. Refused read-only action requests sign nothing. - Completed the explicit A2 requirement for plans on their own book: three independently bounded 4096-entry replay books for reads, plans and OPEN/actions. The server and infraternal agent share the classification, and plan grants use separate per-(user, owning infraternal agent) admission buckets, at the read numeric rates. Legacy OPEN and provider grants retain the 10 s server lifetime. - Retained A7's atomic fence/idempotency mark and the 130 s execution deadline. Corrected the freshness documentation: signing follows the fence commit, so the 10 s lifetime bounds acceptance from signing; a scheduling delay before signing is outside that bound. - Added fixed-time full-book isolation checks in both directions, OPEN/action acceptance with full read/plan books, and plan-book clearing/old-nonce denial after tunnel reset. Admission tests now exercise all three classes at a controlled instant. Added the perf-VM-only warm acceptance/refusal benchmark; no performance measurement or budget certification is claimed. Regression proof: before the split, the test failed with `a full read book must leave plan grants available: ResourceExhausted` (exit 101). Final workspace tests include the strengthened fixed-time and nonce-reset checks. Relevant final test output, quoted verbatim: ```text test unsupported_tampered_stale_binding_and_malformed_calls_fail_before_provider_io ... ok test discovery_inspect_plan_and_action_round_trip_through_the_runtime ... ok test read_flood_cannot_starve_open_or_mutation_grants ... ok test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 83.15s test host_route::tests::admission_ceilings_stay_below_replay_book_capacity ... ok test host_route::tests::admission_is_per_user_and_agent_with_an_agent_ceiling ... ok test host_route::tests::benchmark_grant_admission ... ignored, benchmark only on the perf-test VM; A/B against the base head test storage::fence_tests::container_dispatch_marks_idempotency_inside_the_fence ... ok test tunnel::provider_rpc_tests::read_only_action_flood_signs_nothing_and_leaves_the_owner_working ... ok test result: ok. 114 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 8.45s ``` Required gate command: `nice -n 15 env CARGO_INCREMENTAL=0 CARGO_PROFILE_DEV_DEBUG=0 CARGO_PROFILE_TEST_DEBUG=0 CARGO_BUILD_JOBS=2 INFRATERNAL_VERIFY_RUN_ID=rs-replay-admission scripts/verify fast`. Exit 0. Exact complete gate output: ```text WARN load5=37.26 exceeds online CPU count=8; timing-sensitive checks may be delayed PASS fast: migrations are append-only (2.056s) PASS fast: workspace package dependencies (3.350s) PASS fast: JavaScript dependencies (0.534s) PASS fast: advisory review policy tests (1.458s) SUPPLY_CHAIN_REVIEWS advisory exceptions are within their review windows SUPPLY_CHAIN cargo-deny: cargo-deny 0.20.2 SUPPLY_CHAIN_NOTICES generated THIRD_PARTY_NOTICES.md from 95 frontend packages SUPPLY_CHAIN_NOTICES copied source: 179 shadcn files, 3 calternal-derived files SUPPLY_CHAIN_NOTICES license files: 66 distinct texts; 0 packages need manual license review advisories ok SUPPLY_CHAIN_RUST_ADVISORIES passed with refreshed advisory data licenses ok SUPPLY_CHAIN_RUST_LICENSES passed bun audit v1.4.2 (744846f84) cookie@0.6.0 workspace:@infraternal/web > @sveltejs/kit > cookie low: cookie accepts cookie name, path, and domain with out of bounds characters (<0.7.0) - https://github.com/advisories/GHSA-pxg6-pf52-xh8x 1 vulnerability (1 low) bun audit fix upgrade the vulnerable packages within their ranges bun audit fix --latest also cross major versions SUPPLY_CHAIN_BUN_AUDIT findings reported; this check is report-only SUPPLY_CHAIN_PASS Rust advisory/license checks complete; Bun findings are report-only PASS fast: supply-chain checks (41.606s) PASS fast: build web app (109.051s) PASS fast: cargo fmt --check (5.661s) PASS fast: cargo clippy (996.863s) PASS fast: cargo test (558.788s) PASS fast: svelte-check (49.863s) PASS fast: UI package svelte-check (10.158s) PASS fast: stream package typecheck (15.425s) PASS fast: Vitest (16.905s) PASS fast: UI package Vitest (62.335s) PASS fast: stream package Vitest (3.315s) PASS fast: OpenAPI and TypeScript client drift (188.201s) PASS fast: terminal TypeScript (7.974s) PASS fast: terminal Vitest (2.652s) ``` The low cookie advisory is the existing report-only Bun finding. No dependency changes. No `verify merge`, other full gate, or perf-VM A/B was run; independent review and merge/performance gates remain with the orchestrator. Tooling/host notes: the graph was absent; rebuild and queries were attempted before raw searches, but queries returned no indexed nodes while the database was locked. The owned prolonged rebuild was stopped and direct source/diff review supplied the fallback. The preset root-disk cache was cold. The former worktree target was moved off /mnt/hdd; its obsolete cache was later removed when root free space fell to 8 GB. A temporary root-target symlink supported the gate summary and was removed after the gate. Active build artifacts remain only in the preset root-disk target, outside git.
Author
Owner

Job rs-mutation-safety finished on branch mutation-safety at d0952a66460672cc51b94bd6da47867a7c296d28; original base 450c297. Worktree clean. No push or merge gate.

Retained implementation commit 1f62954; added d0952a6 (real SQLite busy exhaustion/resumption regression). Both commits contain the requested attribution/session trailers.

Finished and verified:

  • D1: sorted per-target locks, 10-second lock timeout -> plan_stale reason lock_timeout for plans, authorization/version recheck under the locks, parameterized bounded dispatch (60-second embedded default). Planned and unplanned mutations share the locks.
  • D2: safe retryable pre-dispatch failures release the idempotency claim; dispatched and unknown outcomes retain protection.
  • D7: CLI mutation response loss/unreadable response -> conflict/outcome_unknown, retryable false, exit 6. Unsent connection failures remain retryable.
  • D10: docs/CLI.md exit-code table, InvalidHost exit 5, unknown/out-of-range exec/SSH exit status -> 1.
  • D15: initial attempt plus three busy retries, then skipped/Busy. Added a real competing SQLite writer test proving zero dispatch/accepted-audit records during contention and success after releasing the writer.

A6 deferred: this branch's resources still dispatch through the legacy engine boundary; no provider binding is available to hash into the plan. Integrate binding freshness with the provider migration rather than inventing a binding here.

Scoped verification (nice -n 15; one test thread):

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 113 filtered out; finished in 0.45s
test result: ok. 112 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 54.19s
test result: ok. 49 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.72s

Final required command: INFRATERNAL_VERIFY_RUN_ID=rs-mutation-safety scripts/verify fast. Environment: CARGO_INCREMENTAL=0, CARGO_PROFILE_DEV_DEBUG=0, CARGO_PROFILE_TEST_DEBUG=0, CARGO_BUILD_JOBS=2, RUST_TEST_THREADS=1; nice -n 15; preset root-disk CARGO_TARGET_DIR. Exit 0. Verbatim gate output:

WARN load5=23.45 exceeds online CPU count=8; timing-sensitive checks may be delayed
PASS fast: migrations are append-only (0.543s)
PASS fast: workspace package dependencies (1.167s)
PASS fast: JavaScript dependencies (1.025s)
PASS fast: advisory review policy tests (0.291s)
SUPPLY_CHAIN_REVIEWS advisory exceptions are within their review windows
SUPPLY_CHAIN cargo-deny: cargo-deny 0.20.2
SUPPLY_CHAIN_NOTICES generated THIRD_PARTY_NOTICES.md from 95 frontend packages
SUPPLY_CHAIN_NOTICES copied source: 179 shadcn files, 3 calternal-derived files
SUPPLY_CHAIN_NOTICES license files: 66 distinct texts; 0 packages need manual license review
advisories ok
SUPPLY_CHAIN_RUST_ADVISORIES passed with refreshed advisory data
licenses ok
SUPPLY_CHAIN_RUST_LICENSES passed
bun audit v1.4.2 (744846f84)

cookie@0.6.0
  workspace:@infraternal/web > @sveltejs/kit > cookie
  low: cookie accepts cookie name, path, and domain with out of bounds characters (<0.7.0) - https://github.com/advisories/GHSA-pxg6-pf52-xh8x

1 vulnerability (1 low)

  bun audit fix           upgrade the vulnerable packages within their ranges
  bun audit fix --latest  also cross major versions
SUPPLY_CHAIN_BUN_AUDIT findings reported; this check is report-only
SUPPLY_CHAIN_PASS Rust advisory/license checks complete; Bun findings are report-only
PASS fast: supply-chain checks (20.616s)
PASS fast: build web app (55.570s)
PASS fast: cargo fmt --check (2.971s)
PASS fast: cargo clippy (123.322s)
PASS fast: cargo test (398.985s)
PASS fast: svelte-check (57.087s)
PASS fast: UI package svelte-check (26.067s)
PASS fast: stream package typecheck (18.453s)
PASS fast: Vitest (20.010s)
PASS fast: UI package Vitest (44.839s)
PASS fast: stream package Vitest (1.749s)
PASS fast: OpenAPI and TypeScript client drift (105.210s)
PASS fast: terminal TypeScript (7.455s)
PASS fast: terminal Vitest (2.265s)

The first fast attempt exited 101 during linking because generated CLI object files were missing. Disk had 19G free; cause was not established. The isolated CLI retry and final fast rerun both passed without source changes. The Bun cookie advisory is report-only; dependencies were not changed in this job. No performance certification or merge/integration/nightly gate is claimed.

Job rs-mutation-safety finished on branch mutation-safety at d0952a66460672cc51b94bd6da47867a7c296d28; original base 450c297. Worktree clean. No push or merge gate. Retained implementation commit 1f62954; added d0952a6 (real SQLite busy exhaustion/resumption regression). Both commits contain the requested attribution/session trailers. Finished and verified: - D1: sorted per-target locks, 10-second lock timeout -> plan_stale reason lock_timeout for plans, authorization/version recheck under the locks, parameterized bounded dispatch (60-second embedded default). Planned and unplanned mutations share the locks. - D2: safe retryable pre-dispatch failures release the idempotency claim; dispatched and unknown outcomes retain protection. - D7: CLI mutation response loss/unreadable response -> conflict/outcome_unknown, retryable false, exit 6. Unsent connection failures remain retryable. - D10: docs/CLI.md exit-code table, InvalidHost exit 5, unknown/out-of-range exec/SSH exit status -> 1. - D15: initial attempt plus three busy retries, then skipped/Busy. Added a real competing SQLite writer test proving zero dispatch/accepted-audit records during contention and success after releasing the writer. A6 deferred: this branch's resources still dispatch through the legacy engine boundary; no provider binding is available to hash into the plan. Integrate binding freshness with the provider migration rather than inventing a binding here. Scoped verification (nice -n 15; one test thread): ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 113 filtered out; finished in 0.45s test result: ok. 112 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 54.19s test result: ok. 49 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.72s ``` Final required command: INFRATERNAL_VERIFY_RUN_ID=rs-mutation-safety scripts/verify fast. Environment: CARGO_INCREMENTAL=0, CARGO_PROFILE_DEV_DEBUG=0, CARGO_PROFILE_TEST_DEBUG=0, CARGO_BUILD_JOBS=2, RUST_TEST_THREADS=1; nice -n 15; preset root-disk CARGO_TARGET_DIR. Exit 0. Verbatim gate output: ```text WARN load5=23.45 exceeds online CPU count=8; timing-sensitive checks may be delayed PASS fast: migrations are append-only (0.543s) PASS fast: workspace package dependencies (1.167s) PASS fast: JavaScript dependencies (1.025s) PASS fast: advisory review policy tests (0.291s) SUPPLY_CHAIN_REVIEWS advisory exceptions are within their review windows SUPPLY_CHAIN cargo-deny: cargo-deny 0.20.2 SUPPLY_CHAIN_NOTICES generated THIRD_PARTY_NOTICES.md from 95 frontend packages SUPPLY_CHAIN_NOTICES copied source: 179 shadcn files, 3 calternal-derived files SUPPLY_CHAIN_NOTICES license files: 66 distinct texts; 0 packages need manual license review advisories ok SUPPLY_CHAIN_RUST_ADVISORIES passed with refreshed advisory data licenses ok SUPPLY_CHAIN_RUST_LICENSES passed bun audit v1.4.2 (744846f84) cookie@0.6.0 workspace:@infraternal/web > @sveltejs/kit > cookie low: cookie accepts cookie name, path, and domain with out of bounds characters (<0.7.0) - https://github.com/advisories/GHSA-pxg6-pf52-xh8x 1 vulnerability (1 low) bun audit fix upgrade the vulnerable packages within their ranges bun audit fix --latest also cross major versions SUPPLY_CHAIN_BUN_AUDIT findings reported; this check is report-only SUPPLY_CHAIN_PASS Rust advisory/license checks complete; Bun findings are report-only PASS fast: supply-chain checks (20.616s) PASS fast: build web app (55.570s) PASS fast: cargo fmt --check (2.971s) PASS fast: cargo clippy (123.322s) PASS fast: cargo test (398.985s) PASS fast: svelte-check (57.087s) PASS fast: UI package svelte-check (26.067s) PASS fast: stream package typecheck (18.453s) PASS fast: Vitest (20.010s) PASS fast: UI package Vitest (44.839s) PASS fast: stream package Vitest (1.749s) PASS fast: OpenAPI and TypeScript client drift (105.210s) PASS fast: terminal TypeScript (7.455s) PASS fast: terminal Vitest (2.265s) ``` The first fast attempt exited 101 during linking because generated CLI object files were missing. Disk had 19G free; cause was not established. The isolated CLI retry and final fast rerun both passed without source changes. The Bun cookie advisory is report-only; dependencies were not changed in this job. No performance certification or merge/integration/nightly gate is claimed.
Author
Owner

rs-remote-ssh resume finished at 576e91e050 on branch remote-ssh. Full findings and verbatim gate/test evidence are posted in kayg/infraternal#49. Added attributed-identity regressions and corrected architecture docs; fixed the completion-audit test fixture to bind its real embedded infraternal agent owner. Real remote SSH test: 1 passed; embedded real-sshd product tests: 4 passed. Final INFRATERNAL_VERIFY_RUN_ID=rs-remote-ssh scripts/verify fast: exit 0, all 18 stages, serial workspace tests (RUST_TEST_THREADS=1), lean two-job nice-15 root-disk build. Clean worktree; no push or merge gate.

rs-remote-ssh resume finished at 576e91e050ba74c39b43cfa52bf2c5eb033d61f4 on branch remote-ssh. Full findings and verbatim gate/test evidence are posted in kayg/infraternal#49. Added attributed-identity regressions and corrected architecture docs; fixed the completion-audit test fixture to bind its real embedded infraternal agent owner. Real remote SSH test: 1 passed; embedded real-sshd product tests: 4 passed. Final INFRATERNAL_VERIFY_RUN_ID=rs-remote-ssh scripts/verify fast: exit 0, all 18 stages, serial workspace tests (RUST_TEST_THREADS=1), lean two-job nice-15 root-disk build. Clean worktree; no push or merge gate.
Author
Owner

Completed resume verification on branch session-authority, head cd7ca3faf07621804f642f8e0f1793f72024e637. Worktree is clean. No push, merge gate, or issue close. No new source commit was necessary: the existing commit already implements A3/A5/A8/A10/A11 and its tests; the previous cargo-test failure did not reproduce in a full workspace run or the final fast gate. The old failing diagnostic was not available in the worktree, so its original test name could not be recovered.

Finished:

  • Verified the one owner-plus-creator-refresh-lineage rule for embedded SSH, embedded exec, and remote exec sweeps, including creator mismatch termination and owner-only audit attribution (A3/A10).
  • Verified events require containers:read and redact exec command text/labels (A5).
  • Verified certificate rotation/revocation checks before tunnel nonce admission (A8).
  • Verified OPEN_OK.session_id creation/reattachment binding (A11).
  • Completed a full cargo test --workspace diagnostic run, exit 0. The real-Docker creator-revocation regression also passed in the existing current-code test executable.
  • Resolved generated dependency-cache errors (SQLx E0460, WebAuthn E0463) without product-source changes. The preset root-cache path became a symlink to the HDD target during the run. After root-disk space recovered, copied this worktree's generated cache to the actual root-disk directory /home/kayg/.cache/infraternal-targets/rs-session-authority-resume and rebuilt affected SQLx/either/WebAuthn/OpenSSL packages. The prior environment blockage is resolved.

Final gate command (exit 0):

env CARGO_TARGET_DIR=/home/kayg/.cache/infraternal-targets/rs-session-authority-resume CARGO_INCREMENTAL=0 CARGO_PROFILE_DEV_DEBUG=0 CARGO_PROFILE_TEST_DEBUG=0 CARGO_BUILD_JOBS=2 CARGO_TERM_QUIET=true INFRATERNAL_VERIFY_RUN_ID=rs-session-authority nice -n 15 scripts/verify fast

Final gate output, verbatim:

WARN load5=15.79 exceeds online CPU count=8; timing-sensitive checks may be delayed
PASS fast: migrations are append-only (0.372s)
PASS fast: workspace package dependencies (0.418s)
PASS fast: JavaScript dependencies (0.246s)
PASS fast: advisory review policy tests (0.198s)
SUPPLY_CHAIN_REVIEWS advisory exceptions are within their review windows
SUPPLY_CHAIN cargo-deny: cargo-deny 0.20.2
SUPPLY_CHAIN_NOTICES generated THIRD_PARTY_NOTICES.md from 95 frontend packages
SUPPLY_CHAIN_NOTICES copied source: 179 shadcn files, 3 calternal-derived files
SUPPLY_CHAIN_NOTICES license files: 66 distinct texts; 0 packages need manual license review
advisories ok
SUPPLY_CHAIN_RUST_ADVISORIES passed with refreshed advisory data
licenses ok
SUPPLY_CHAIN_RUST_LICENSES passed
bun audit v1.4.2 (744846f84)

cookie@0.6.0
  workspace:@infraternal/web > @sveltejs/kit > cookie
  low: cookie accepts cookie name, path, and domain with out of bounds characters (<0.7.0) - https://github.com/advisories/GHSA-pxg6-pf52-xh8x

1 vulnerability (1 low)

  bun audit fix           upgrade the vulnerable packages within their ranges
  bun audit fix --latest  also cross major versions
SUPPLY_CHAIN_BUN_AUDIT findings reported; this check is report-only
SUPPLY_CHAIN_PASS Rust advisory/license checks complete; Bun findings are report-only
PASS fast: supply-chain checks (5.021s)
PASS fast: build web app (24.008s)
PASS fast: cargo fmt --check (1.278s)
PASS fast: cargo clippy (25.595s)
PASS fast: cargo test (184.308s)
PASS fast: svelte-check (22.314s)
PASS fast: UI package svelte-check (6.091s)
PASS fast: stream package typecheck (5.723s)
PASS fast: Vitest (6.558s)
PASS fast: UI package Vitest (11.866s)
PASS fast: stream package Vitest (0.758s)
PASS fast: OpenAPI and TypeScript client drift (54.485s)
PASS fast: terminal TypeScript (4.254s)
PASS fast: terminal Vitest (1.582s)

The Bun low-severity cookie finding above is report-only under the existing gate policy. Fast passing is not a merge-gate or perf-test-VM A/B claim.

Additional diagnostic evidence, verbatim:

test revoking_ai_agent_creator_terminates_embedded_persistent_exec ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 20 filtered out; finished in 7.85s

Cache-repair references: Rust E0460, Rust E0463, package-scoped Cargo cleanup.

Completed resume verification on branch `session-authority`, head `cd7ca3faf07621804f642f8e0f1793f72024e637`. Worktree is clean. No push, merge gate, or issue close. No new source commit was necessary: the existing commit already implements A3/A5/A8/A10/A11 and its tests; the previous cargo-test failure did not reproduce in a full workspace run or the final fast gate. The old failing diagnostic was not available in the worktree, so its original test name could not be recovered. Finished: - Verified the one owner-plus-creator-refresh-lineage rule for embedded SSH, embedded exec, and remote exec sweeps, including creator mismatch termination and owner-only audit attribution (A3/A10). - Verified events require `containers:read` and redact exec command text/labels (A5). - Verified certificate rotation/revocation checks before tunnel nonce admission (A8). - Verified `OPEN_OK.session_id` creation/reattachment binding (A11). - Completed a full `cargo test --workspace` diagnostic run, exit 0. The real-Docker creator-revocation regression also passed in the existing current-code test executable. - Resolved generated dependency-cache errors (SQLx E0460, WebAuthn E0463) without product-source changes. The preset root-cache path became a symlink to the HDD target during the run. After root-disk space recovered, copied this worktree's generated cache to the actual root-disk directory `/home/kayg/.cache/infraternal-targets/rs-session-authority-resume` and rebuilt affected SQLx/`either`/WebAuthn/OpenSSL packages. The prior environment blockage is resolved. Final gate command (exit 0): ```sh env CARGO_TARGET_DIR=/home/kayg/.cache/infraternal-targets/rs-session-authority-resume CARGO_INCREMENTAL=0 CARGO_PROFILE_DEV_DEBUG=0 CARGO_PROFILE_TEST_DEBUG=0 CARGO_BUILD_JOBS=2 CARGO_TERM_QUIET=true INFRATERNAL_VERIFY_RUN_ID=rs-session-authority nice -n 15 scripts/verify fast ``` Final gate output, verbatim: ```text WARN load5=15.79 exceeds online CPU count=8; timing-sensitive checks may be delayed PASS fast: migrations are append-only (0.372s) PASS fast: workspace package dependencies (0.418s) PASS fast: JavaScript dependencies (0.246s) PASS fast: advisory review policy tests (0.198s) SUPPLY_CHAIN_REVIEWS advisory exceptions are within their review windows SUPPLY_CHAIN cargo-deny: cargo-deny 0.20.2 SUPPLY_CHAIN_NOTICES generated THIRD_PARTY_NOTICES.md from 95 frontend packages SUPPLY_CHAIN_NOTICES copied source: 179 shadcn files, 3 calternal-derived files SUPPLY_CHAIN_NOTICES license files: 66 distinct texts; 0 packages need manual license review advisories ok SUPPLY_CHAIN_RUST_ADVISORIES passed with refreshed advisory data licenses ok SUPPLY_CHAIN_RUST_LICENSES passed bun audit v1.4.2 (744846f84) cookie@0.6.0 workspace:@infraternal/web > @sveltejs/kit > cookie low: cookie accepts cookie name, path, and domain with out of bounds characters (<0.7.0) - https://github.com/advisories/GHSA-pxg6-pf52-xh8x 1 vulnerability (1 low) bun audit fix upgrade the vulnerable packages within their ranges bun audit fix --latest also cross major versions SUPPLY_CHAIN_BUN_AUDIT findings reported; this check is report-only SUPPLY_CHAIN_PASS Rust advisory/license checks complete; Bun findings are report-only PASS fast: supply-chain checks (5.021s) PASS fast: build web app (24.008s) PASS fast: cargo fmt --check (1.278s) PASS fast: cargo clippy (25.595s) PASS fast: cargo test (184.308s) PASS fast: svelte-check (22.314s) PASS fast: UI package svelte-check (6.091s) PASS fast: stream package typecheck (5.723s) PASS fast: Vitest (6.558s) PASS fast: UI package Vitest (11.866s) PASS fast: stream package Vitest (0.758s) PASS fast: OpenAPI and TypeScript client drift (54.485s) PASS fast: terminal TypeScript (4.254s) PASS fast: terminal Vitest (1.582s) ``` The Bun low-severity cookie finding above is report-only under the existing gate policy. Fast passing is not a merge-gate or perf-test-VM A/B claim. Additional diagnostic evidence, verbatim: ```text test revoking_ai_agent_creator_terminates_embedded_persistent_exec ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 20 filtered out; finished in 7.85s ``` Cache-repair references: [Rust E0460](https://doc.rust-lang.org/error_codes/E0460.html), [Rust E0463](https://doc.rust-lang.org/error_codes/E0463.html), [package-scoped Cargo cleanup](https://doc.rust-lang.org/cargo/commands/cargo-clean.html).
Author
Owner

Browser verification is pending on shared VM capacity. The production web build, node --check scripts/browser-check.mjs, and git diff --check passed. I have not started the release browser gate: the recorded run guidance requires load5 below 8 and no concurrent merge/integration/browser or cargo build, while at 2026-10-03 14:40 UTC load5 is 16.47 and other fast/merge gates are active. I will resume the browser gate when the VM clears.

Browser verification is pending on shared VM capacity. The production web build, `node --check scripts/browser-check.mjs`, and `git diff --check` passed. I have not started the release browser gate: the recorded run guidance requires load5 below 8 and no concurrent merge/integration/browser or cargo build, while at 2026-10-03 14:40 UTC load5 is 16.47 and other fast/merge gates are active. I will resume the browser gate when the VM clears.
Author
Owner

Resuming rs-port in /home/kayg/wt/calternal-port on branch calternal-port, from the authorized resume head 76db2155548b. The worktree already has an uncommitted scripts/browser-check.mjs change from the previous run; I am preserving it and checking the build before changing it. /mnt/hdd has 8.1 GB free (the stop threshold is 5 GB); Cargo targets remain on the root disk. I will finish the production browser check with condition-based waits and then run INFRATERAL_VERIFY_RUN_ID=rs-port scripts/verify fast.

Resuming rs-port in `/home/kayg/wt/calternal-port` on branch `calternal-port`, from the authorized resume head `76db2155548b`. The worktree already has an uncommitted `scripts/browser-check.mjs` change from the previous run; I am preserving it and checking the build before changing it. `/mnt/hdd` has 8.1 GB free (the stop threshold is 5 GB); Cargo targets remain on the root disk. I will finish the production browser check with condition-based waits and then run `INFRATERAL_VERIFY_RUN_ID=rs-port scripts/verify fast`.
Author
Owner

Build/fast check at resume head 76db2155548b (worktree edit is still only the prior scripts/browser-check.mjs refactor) exited 0. This confirms the web build and the Rust/UI package checks pass before the release-browser tier.

PASS fast: migrations are append-only (0.153s)
PASS fast: workspace package dependencies (0.254s)
PASS fast: JavaScript dependencies (0.012s)
PASS fast: build web app (11.222s)
PASS fast: cargo fmt --check (1.575s)
PASS fast: cargo clippy (420.486s)
PASS fast: cargo test (330.335s)
PASS fast: svelte-check (15.909s)
PASS fast: UI package svelte-check (5.427s)
PASS fast: stream package typecheck (6.784s)
PASS fast: Vitest (5.609s)
PASS fast: UI package Vitest (6.006s)
PASS fast: stream package Vitest (1.534s)
PASS fast: OpenAPI and TypeScript client drift (76.455s)
PASS fast: terminal TypeScript (6.486s)
PASS fast: terminal Vitest (3.248s)
Build/fast check at resume head `76db2155548b` (worktree edit is still only the prior `scripts/browser-check.mjs` refactor) exited 0. This confirms the web build and the Rust/UI package checks pass before the release-browser tier. ```text PASS fast: migrations are append-only (0.153s) PASS fast: workspace package dependencies (0.254s) PASS fast: JavaScript dependencies (0.012s) PASS fast: build web app (11.222s) PASS fast: cargo fmt --check (1.575s) PASS fast: cargo clippy (420.486s) PASS fast: cargo test (330.335s) PASS fast: svelte-check (15.909s) PASS fast: UI package svelte-check (5.427s) PASS fast: stream package typecheck (6.784s) PASS fast: Vitest (5.609s) PASS fast: UI package Vitest (6.006s) PASS fast: stream package Vitest (1.534s) PASS fast: OpenAPI and TypeScript client drift (76.455s) PASS fast: terminal TypeScript (6.486s) PASS fast: terminal Vitest (3.248s) ```
Author
Owner

The initial fast/build check passed. I am holding the release-browser gate per the resume note's serialization condition: at 16:44 UTC another worktree had an active cargo build --release and a second worktree had Cargo tests running; load average was 10.95 / 11.75 / 10.65. I did not touch those processes. The current browser-check diff contains no waitForTimeout or networkidle; I will start the production browser gate after the competing build/test work and load have cleared.

The initial fast/build check passed. I am holding the release-browser gate per the resume note's serialization condition: at 16:44 UTC another worktree had an active `cargo build --release` and a second worktree had Cargo tests running; load average was 10.95 / 11.75 / 10.65. I did not touch those processes. The current browser-check diff contains no `waitForTimeout` or `networkidle`; I will start the production browser gate after the competing build/test work and load have cleared.
Author
Owner

Resuming rs-port in /home/kayg/wt/calternal-port. Branch: calternal-port. Base head: 76db215. The remaining work is the calternal UI port: finish the production-browser check, fix the three auth/stream lifecycle findings from the handoff with Vitest coverage, then run the requested browser check and verify fast.

Resuming rs-port in /home/kayg/wt/calternal-port. Branch: calternal-port. Base head: 76db215. The remaining work is the calternal UI port: finish the production-browser check, fix the three auth/stream lifecycle findings from the handoff with Vitest coverage, then run the requested browser check and verify fast.
Author
Owner

Starting issue #46 on branch ui-datatable, based on calternal-port at 76db2155548b1f1d831516dc1a9fde7f471108f2. Scope is the shared DataTable in packages/ui and the Containers and Hosts list pages, with browser, test, and performance evidence recorded here at completion.

Starting issue #46 on branch `ui-datatable`, based on `calternal-port` at `76db2155548b1f1d831516dc1a9fde7f471108f2`. Scope is the shared DataTable in `packages/ui` and the Containers and Hosts list pages, with browser, test, and performance evidence recorded here at completion.
Author
Owner

Resuming issue #46 in worktree /mnt/hdd/infraternal/wt-lp/ui-datatable on branch ui-datatable, based on the calternal-port head 76db2155548b1f1d831516dc1a9fde7f471108f2. The worktree is clean at that head. /mnt/hdd has 16 GiB free, above the 6 GiB build cutoff. Continuing the DataTable implementation and required UI/browser verification from the current state. The worktree has no local code-review-graph index; the resume instruction forbids graph builds, so I will use targeted source searches where needed.

Resuming issue #46 in worktree `/mnt/hdd/infraternal/wt-lp/ui-datatable` on branch `ui-datatable`, based on the `calternal-port` head `76db2155548b1f1d831516dc1a9fde7f471108f2`. The worktree is clean at that head. `/mnt/hdd` has 16 GiB free, above the 6 GiB build cutoff. Continuing the DataTable implementation and required UI/browser verification from the current state. The worktree has no local code-review-graph index; the resume instruction forbids graph builds, so I will use targeted source searches where needed.
Author
Owner

Resuming rs-port on branch calternal-port.

Base/worktree head from the resume note: 76db2155548b1f1d831516dc1a9fde7f471108f2 (owner-approved bfcache reload behavior). origin/dev is d4fee7ba2fa24d5dc55c0cbd22750c065df4668b.

Preserving the inherited uncommitted changes in scripts/browser-check.mjs, packages/web/src/hooks.client.ts, and packages/web/src/lib/page-lifecycle.ts. Scope: build first, finish the release-browser check without fixed sleeps/networkidle, and address the three listed auth/page lifecycle majors with Vitest cases. No enterprise restyle. Disk check: / has 22 GB free and /mnt/hdd has 16 GB free. I will report gate output and the final head when complete.

Resuming rs-port on branch `calternal-port`. Base/worktree head from the resume note: `76db2155548b1f1d831516dc1a9fde7f471108f2` (owner-approved bfcache reload behavior). `origin/dev` is `d4fee7ba2fa24d5dc55c0cbd22750c065df4668b`. Preserving the inherited uncommitted changes in `scripts/browser-check.mjs`, `packages/web/src/hooks.client.ts`, and `packages/web/src/lib/page-lifecycle.ts`. Scope: build first, finish the release-browser check without fixed sleeps/networkidle, and address the three listed auth/page lifecycle majors with Vitest cases. No enterprise restyle. Disk check: `/` has 22 GB free and `/mnt/hdd` has 16 GB free. I will report gate output and the final head when complete.
Author
Owner

Evidence and fixes for the three reload review majors:

  • Chromium's recorded bfcache ordering is pagehide → hidden/visible visibilitychange → persisted pageshow. The shared lifecycle fence now registers from client bootstrap and auth/API startup; visible pollers and API dispatch require an active document. Persisted pageshow requests the fresh reload.
  • Stream recovery rechecks document activity after auth recovery and connection awaits. A suspended document cannot create a replacement stream client or open attachments.
  • The peer-session wait now checks the original sign-out epoch after every await. A sign-out wake returns cancellation before any shared-cookie refresh.

Regression command:
nice -n 15 rtk bun run --cwd=packages/web test -- src/lib/visible-poller.test.ts src/lib/api.test.ts src/lib/auth.test.ts src/lib/stream-attachment.test.ts

Output:

 Test Files  4 passed (4)
      Tests  38 passed (38)
   Duration  1.82s (tests 76%, transform 20%, import 3%, worker 1%)

Additional checks: svelte-check found 0 errors and 0 warnings; the production web build exited 0 (✓ built in 8.42s, adapter-static wrote build). Browser harness routes now wait for #route-content or .auth-screen after domcontentloaded; current source contains no networkidle, waitForTimeout, or setTimeout( waits. No product budget constants were changed. Full release-browser gate is next.

Evidence and fixes for the three reload review majors: - Chromium's recorded bfcache ordering is `pagehide` → hidden/visible `visibilitychange` → persisted `pageshow`. The shared lifecycle fence now registers from client bootstrap and auth/API startup; visible pollers and API dispatch require an active document. Persisted `pageshow` requests the fresh reload. - Stream recovery rechecks document activity after auth recovery and connection awaits. A suspended document cannot create a replacement stream client or open attachments. - The peer-session wait now checks the original sign-out epoch after every await. A sign-out wake returns cancellation before any shared-cookie refresh. Regression command: `nice -n 15 rtk bun run --cwd=packages/web test -- src/lib/visible-poller.test.ts src/lib/api.test.ts src/lib/auth.test.ts src/lib/stream-attachment.test.ts` Output: ```text Test Files 4 passed (4) Tests 38 passed (38) Duration 1.82s (tests 76%, transform 20%, import 3%, worker 1%) ``` Additional checks: `svelte-check found 0 errors and 0 warnings`; the production web build exited 0 (`✓ built in 8.42s`, adapter-static wrote `build`). Browser harness routes now wait for `#route-content` or `.auth-screen` after `domcontentloaded`; current source contains no `networkidle`, `waitForTimeout`, or `setTimeout(` waits. No product budget constants were changed. Full release-browser gate is next.
Author
Owner

Starting multitab-refresh on branch multitab-refresh; base origin/dev and HEAD d4fee7ba2f. Investigating product vs browser-check races, preserving exactly one refresh, adding Vitest regression coverage and 30 loaded multi-tab runs, then scripts/verify fast. Only writer; no push.

Starting multitab-refresh on branch multitab-refresh; base origin/dev and HEAD d4fee7ba2fa24d5dc55c0cbd22750c065df4668b. Investigating product vs browser-check races, preserving exactly one refresh, adding Vitest regression coverage and 30 loaded multi-tab runs, then scripts/verify fast. Only writer; no push.
Author
Owner

The first release-browser gate built the release binary and passed the terminal fixture, then failed in the Playwright stage after 8.468s with error: evaluate: Execution context was destroyed, most likely because of a navigation. It captured the anonymous setup/sign-in screenshots and reached a successful setup-account sign-out; I am rerunning with the temporary stage log preserved to identify the exact flow. Disk at failure: / 185 GB free, /mnt/hdd 200 GB free.

The first release-browser gate built the release binary and passed the terminal fixture, then failed in the Playwright stage after 8.468s with `error: evaluate: Execution context was destroyed, most likely because of a navigation`. It captured the anonymous setup/sign-in screenshots and reached a successful setup-account sign-out; I am rerunning with the temporary stage log preserved to identify the exact flow. Disk at failure: `/` 185 GB free, `/mnt/hdd` 200 GB free.
Author
Owner

Product races reproduced with Vitest: four regression checks fail on base implementation (idle signed-in broadcast adoption, storage newer before recovery, timeout causing another refresh, sign-out during generation wait causing another refresh). No refresh timer exists in auth.svelte.ts: refresh is initialization/401 driven. The provided production log contains refresh/401 cascades involving the original tab as well as both cold tabs. Current fix adopts successors in idle signed-in tabs, compares generation to the held credential, and returns without rotating after a failed generation wait. Contract clarification is separate commit b8b8cf1, for independent review before integration. Browser smoke now waits for two actual native lock requests rather than 200 ms, keeps the original poll active, counts every context refresh, and waits for all three pages to successfully use one public successor token ID. Sources: https://www.w3.org/TR/web-locks/ (lock held until callback settles); https://html.spec.whatwg.org/multipage/web-messaging.html#broadcasting-to-other-browsing-contexts (queued broadcast tasks); https://playwright.dev/docs/api/class-route#route-fetch (fetch without fulfilling). Four regressions pass after the minimal product fix; further simultaneous-tab coverage and loaded production checks pending.

Product races reproduced with Vitest: four regression checks fail on base implementation (idle signed-in broadcast adoption, storage newer before recovery, timeout causing another refresh, sign-out during generation wait causing another refresh). No refresh timer exists in auth.svelte.ts: refresh is initialization/401 driven. The provided production log contains refresh/401 cascades involving the original tab as well as both cold tabs. Current fix adopts successors in idle signed-in tabs, compares generation to the held credential, and returns without rotating after a failed generation wait. Contract clarification is separate commit b8b8cf1, for independent review before integration. Browser smoke now waits for two actual native lock requests rather than 200 ms, keeps the original poll active, counts every context refresh, and waits for all three pages to successfully use one public successor token ID. Sources: https://www.w3.org/TR/web-locks/ (lock held until callback settles); https://html.spec.whatwg.org/multipage/web-messaging.html#broadcasting-to-other-browsing-contexts (queued broadcast tasks); https://playwright.dev/docs/api/class-route#route-fetch (fetch without fulfilling). Four regressions pass after the minimal product fix; further simultaneous-tab coverage and loaded production checks pending.
Author
Owner

Verification finding (2026-10-03): INFRATERNA_VERIFY_RUN_ID=ui-datatable scripts/verify fast passed the web build, then failed the workspace Clippy stage on six existing assert!(!value.is_empty()) checks in crates/engine/tests/integration.rs (lines 1157, 1567, 1662, 1768, 2111, 2154). This UI branch did not modify that file.

Gate output:

PASS fast: build web app (13.271s)
PASS fast: cargo fmt --check (2.242s)
FAIL fast: cargo clippy (158.364s)
error: used `assert!` to check that a value is not empty
    --> crates/engine/tests/integration.rs:1157:5
error: used `assert!` to check that a value is not empty
    --> crates/engine/tests/integration.rs:1567:9
error: used `assert!` to check that a value is not empty
    --> crates/engine/tests/integration.rs:1662:9
error: used `assert!` to check that a value is not empty
    --> crates/engine/tests/integration.rs:1768:9
error: used `assert!` to check that a value is not empty
    --> crates/engine/tests/integration.rs:2111:9
error: used `assert!` to check that a value is not empty
    --> crates/engine/tests/integration.rs:2154:9
Verification finding (2026-10-03): `INFRATERNA_VERIFY_RUN_ID=ui-datatable scripts/verify fast` passed the web build, then failed the workspace Clippy stage on six existing `assert!(!value.is_empty())` checks in `crates/engine/tests/integration.rs` (lines 1157, 1567, 1662, 1768, 2111, 2154). This UI branch did not modify that file. Gate output: ```text PASS fast: build web app (13.271s) PASS fast: cargo fmt --check (2.242s) FAIL fast: cargo clippy (158.364s) error: used `assert!` to check that a value is not empty --> crates/engine/tests/integration.rs:1157:5 error: used `assert!` to check that a value is not empty --> crates/engine/tests/integration.rs:1567:9 error: used `assert!` to check that a value is not empty --> crates/engine/tests/integration.rs:1662:9 error: used `assert!` to check that a value is not empty --> crates/engine/tests/integration.rs:1768:9 error: used `assert!` to check that a value is not empty --> crates/engine/tests/integration.rs:2111:9 error: used `assert!` to check that a value is not empty --> crates/engine/tests/integration.rs:2154:9 ```
Author
Owner

calternal-port mapping inspected directly at its branch head: auth.svelte.ts retains the same pending-only adoption predicate and generation-wait fallthrough, plus session_request and pagehide/pageshow reload handling. Port the signed-in-or-eligible-pending adoption predicate, preserve signOutEpoch fences after every await, and prevent timeout/sign-out fallthrough after a rotation known to complete during this refresh attempt (or newer than a held access credential). Preserve session_request and BFCache reload code. Its cold-start generation=0 intentionally queries historical generations from live peers; historical storage with no live peer must remain distinguishable from a rotation completed during the current lock wait, otherwise a blanket timeout return would strand cold tabs. The Vitest lock-before-broadcast and sign-out-wait tests apply unchanged conceptually; port stale-401 and idle-broadcast tests too. Browser smoke uses real native lock query and shared successor public IDs, independent of UI store internals; update Dashboard/auth locators to the port shell as needed.

calternal-port mapping inspected directly at its branch head: auth.svelte.ts retains the same pending-only adoption predicate and generation-wait fallthrough, plus session_request and pagehide/pageshow reload handling. Port the signed-in-or-eligible-pending adoption predicate, preserve signOutEpoch fences after every await, and prevent timeout/sign-out fallthrough after a rotation known to complete during this refresh attempt (or newer than a held access credential). Preserve session_request and BFCache reload code. Its cold-start generation=0 intentionally queries historical generations from live peers; historical storage with no live peer must remain distinguishable from a rotation completed during the current lock wait, otherwise a blanket timeout return would strand cold tabs. The Vitest lock-before-broadcast and sign-out-wait tests apply unchanged conceptually; port stale-401 and idle-broadcast tests too. Browser smoke uses real native lock query and shared successor public IDs, independent of UI store internals; update Dashboard/auth locators to the port shell as needed.
Author
Owner

The release browser retry built the release binary in 704.754s and passed the terminal fixture in 99.131s. Playwright reached the multi-tab auth flow, then made no progress for over ten minutes after one intercepted refresh; the captured server log showed setup/sign-in/sign-out succeeded, with no later auth transaction. I stopped only this job's hung gate. I changed the lock-queue observation to use Playwright waitForFunction from the waiting tab, retaining the 45s condition timeout so a stalled evaluation releases the response gate. Retrying the release browser gate now.

The release browser retry built the release binary in 704.754s and passed the terminal fixture in 99.131s. Playwright reached the multi-tab auth flow, then made no progress for over ten minutes after one intercepted refresh; the captured server log showed setup/sign-in/sign-out succeeded, with no later auth transaction. I stopped only this job's hung gate. I changed the lock-queue observation to use Playwright `waitForFunction` from the waiting tab, retaining the 45s condition timeout so a stalled evaluation releases the response gate. Retrying the release browser gate now.
Author
Owner

Fast gate result on this branch: web build and rustfmt pass; Clippy fails on nine assert_is_empty lints in untouched tests:

  • crates/engine/tests/integration.rs: lines 1157, 1567, 1662, 1768, 2111, 2154
  • crates/proto/src/stream/controls.rs: line 1409
  • crates/proto/src/stream/records.rs: lines 314, 351

The gate output ends with "error: could not compile infraternal-proto (lib test) due to 3 previous errors"; the engine integration target reports six previous errors. No files in those crates are changed by this job.

Fast gate result on this branch: web build and rustfmt pass; Clippy fails on nine assert_is_empty lints in untouched tests: - crates/engine/tests/integration.rs: lines 1157, 1567, 1662, 1768, 2111, 2154 - crates/proto/src/stream/controls.rs: line 1409 - crates/proto/src/stream/records.rs: lines 314, 351 The gate output ends with "error: could not compile infraternal-proto (lib test) due to 3 previous errors"; the engine integration target reports six previous errors. No files in those crates are changed by this job.
Author
Owner

Production browser gate passed on head 107e502 (focused multi-tab app checks plus the required terminal fixture and production budget stages). Invocation: RUSTC_WRAPPER= CARGO_INCREMENTAL=0 INFRATERNAL_VERIFY_RUN_ID=multitab-refresh-browser INFRATERNAL_MULTITAB_ONLY=1 scripts/verify browser. The first run passed all stages but exited 2 after editing the running shell script; this stable rerun exited 0. Real gate output:

PASS browser: JavaScript dependencies (0.049s)
PASS browser: build web app (30.975s)
PASS browser: build release binary (410.233s)
PASS browser: install Chromium and system dependencies (4.936s)
PASS browser: terminal fixture Playwright (62.640s)
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=1/1
PASS browser: Playwright against release server (12.238s)
PASS browser: terminal production first-load budget (3.193s)

VM screenshot artifacts inspected: /mnt/hdd/infraternal/artifacts/verify/multitab-refresh-browser/browser/multi-tab-supported-1440x900.png and multi-tab-supported-390x844.png. Existing fallback notices captured at both widths as well. Applied UI skill rules: Emil invisible correctness/instant feedback; better-accessibility accessible names and existing status live region; better-layout/typography narrow-width wrapping; better-ui/colors reuse existing tokens and surfaces; better-writing preserve consistent notice vocabulary; better-interface evidence scoped to this auth flow. No visual source changes or broad accessibility/color audit claimed; Safari/iOS remain owner checks.

Eight-worker stress-ng load is active for 30 targeted production multi-tab repetitions; fast gate follows after stopping it.

Production browser gate passed on head 107e502 (focused multi-tab app checks plus the required terminal fixture and production budget stages). Invocation: RUSTC_WRAPPER= CARGO_INCREMENTAL=0 INFRATERNAL_VERIFY_RUN_ID=multitab-refresh-browser INFRATERNAL_MULTITAB_ONLY=1 scripts/verify browser. The first run passed all stages but exited 2 after editing the running shell script; this stable rerun exited 0. Real gate output: ```text PASS browser: JavaScript dependencies (0.049s) PASS browser: build web app (30.975s) PASS browser: build release binary (410.233s) PASS browser: install Chromium and system dependencies (4.936s) PASS browser: terminal fixture Playwright (62.640s) PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=1/1 PASS browser: Playwright against release server (12.238s) PASS browser: terminal production first-load budget (3.193s) ``` VM screenshot artifacts inspected: /mnt/hdd/infraternal/artifacts/verify/multitab-refresh-browser/browser/multi-tab-supported-1440x900.png and multi-tab-supported-390x844.png. Existing fallback notices captured at both widths as well. Applied UI skill rules: Emil invisible correctness/instant feedback; better-accessibility accessible names and existing status live region; better-layout/typography narrow-width wrapping; better-ui/colors reuse existing tokens and surfaces; better-writing preserve consistent notice vocabulary; better-interface evidence scoped to this auth flow. No visual source changes or broad accessibility/color audit claimed; Safari/iOS remain owner checks. Eight-worker stress-ng load is active for 30 targeted production multi-tab repetitions; fast gate follows after stopping it.
Author
Owner

Finished ui-datatable.

Head SHA: 48635904c8

Commits:

  • f4f1dfc feat(ui): add reusable virtualized data table
  • 4863590 feat(web): use data table for container and host lists

The shared table now powers Containers and Hosts, with virtualized dense rows, sorting, text and filter controls, column visibility, selection, keyboard navigation, live status presentation, and responsive columns. Container bulk actions use the existing plan/execute and confirmation flow.

Verification:

  • UI: Test Files 3 passed (3); Tests 10 passed (10).
  • Web: svelte-check found 0 errors and 0 warnings; Test Files 13 passed (13); Tests 69 passed (69).
  • Browser: PASS focused DataTable browser: light/dark desktop/mobile screenshots, sort, keyboard navigation, three-row selection, bulk Stop plan/confirmation/execute
  • Fast gate output excerpt, verbatim:
    PASS fast: build web app (11.622s)
    PASS fast: cargo fmt --check (1.190s)
    FAIL fast: cargo clippy (7.000s)
    error: used assert! to check that a value is not empty
    --> crates/engine/tests/integration.rs:1157:5
    error: could not compile infraternal-engine (test "integration") due to 6 previous errors
    error: could not compile infraternal-proto (lib test) due to 3 previous errors

The Clippy failures are assert_is_empty lints in untouched engine/proto tests.

Cold route JS after:

  • /hosts: 112,673 bytes gzip
  • /containers: 117,985 bytes gzip

A pre-change cold-JS measurement was not present in the issue history or saved artifact logs, so there is no verified before value to report.

Screenshots:

  • /mnt/hdd/infraternal/artifacts/ui-datatable/light-1440x900-containers.png
  • /mnt/hdd/infraternal/artifacts/ui-datatable/light-390x844-containers.png
  • /mnt/hdd/infraternal/artifacts/ui-datatable/dark-1440x900-containers.png
  • /mnt/hdd/infraternal/artifacts/ui-datatable/dark-390x844-containers.png
  • /mnt/hdd/infraternal/artifacts/ui-datatable/light-1440x900-hosts.png
  • /mnt/hdd/infraternal/artifacts/ui-datatable/light-390x844-hosts.png
  • /mnt/hdd/infraternal/artifacts/ui-datatable/dark-1440x900-hosts.png
  • /mnt/hdd/infraternal/artifacts/ui-datatable/dark-390x844-hosts.png

UI rules applied: Emil Design Engineering and better-ui, better-layout, better-typography, better-colors, better-accessibility, better-writing, better-interface. The table reuses shared tokens, keeps a compact grid, preserves deliberate truncation and responsive columns, gives controls accessible names and keyboard focus, and announces state changes through a live region.

Finished ui-datatable. Head SHA: 48635904c8410ca24cbe1ca5a5e13828d5cb55b2 Commits: - f4f1dfc feat(ui): add reusable virtualized data table - 4863590 feat(web): use data table for container and host lists The shared table now powers Containers and Hosts, with virtualized dense rows, sorting, text and filter controls, column visibility, selection, keyboard navigation, live status presentation, and responsive columns. Container bulk actions use the existing plan/execute and confirmation flow. Verification: - UI: Test Files 3 passed (3); Tests 10 passed (10). - Web: svelte-check found 0 errors and 0 warnings; Test Files 13 passed (13); Tests 69 passed (69). - Browser: PASS focused DataTable browser: light/dark desktop/mobile screenshots, sort, keyboard navigation, three-row selection, bulk Stop plan/confirmation/execute - Fast gate output excerpt, verbatim: PASS fast: build web app (11.622s) PASS fast: cargo fmt --check (1.190s) FAIL fast: cargo clippy (7.000s) error: used assert! to check that a value is not empty --> crates/engine/tests/integration.rs:1157:5 error: could not compile infraternal-engine (test "integration") due to 6 previous errors error: could not compile infraternal-proto (lib test) due to 3 previous errors The Clippy failures are assert_is_empty lints in untouched engine/proto tests. Cold route JS after: - /hosts: 112,673 bytes gzip - /containers: 117,985 bytes gzip A pre-change cold-JS measurement was not present in the issue history or saved artifact logs, so there is no verified before value to report. Screenshots: - /mnt/hdd/infraternal/artifacts/ui-datatable/light-1440x900-containers.png - /mnt/hdd/infraternal/artifacts/ui-datatable/light-390x844-containers.png - /mnt/hdd/infraternal/artifacts/ui-datatable/dark-1440x900-containers.png - /mnt/hdd/infraternal/artifacts/ui-datatable/dark-390x844-containers.png - /mnt/hdd/infraternal/artifacts/ui-datatable/light-1440x900-hosts.png - /mnt/hdd/infraternal/artifacts/ui-datatable/light-390x844-hosts.png - /mnt/hdd/infraternal/artifacts/ui-datatable/dark-1440x900-hosts.png - /mnt/hdd/infraternal/artifacts/ui-datatable/dark-390x844-hosts.png UI rules applied: Emil Design Engineering and better-ui, better-layout, better-typography, better-colors, better-accessibility, better-writing, better-interface. The table reuses shared tokens, keeps a compact grid, preserves deliberate truncation and responsive columns, gives controls accessible names and keyboard focus, and announces state changes through a live region.
Author
Owner

Final update after aligning Host filtering with the requested chip controls.

Head SHA: 8632a042de
The branch is clean. The follow-up commit is 8632a04 (fix(web): show host filter chips); it also verifies host chip selection and reset in the browser flow.

Final verification:

  • UI tests: 3 files and 10 tests passed.
  • Web: svelte-check found 0 errors and 0 warnings; 13 files and 69 tests passed.
  • Focused real-browser flow: PASS focused DataTable browser: light/dark desktop/mobile screenshots, sort, keyboard navigation, three-row selection, bulk Stop plan/confirmation/execute
  • Fast gate output excerpt, verbatim:
    PASS fast: build web app (13.320s)
    PASS fast: cargo fmt --check (1.554s)
    FAIL fast: cargo clippy (6.371s)

Clippy reports nine assert_is_empty lints in untouched engine/proto tests: six in crates/engine/tests/integration.rs and three in crates/proto/src/stream/controls.rs and crates/proto/src/stream/records.rs.

Final cold route JS:

  • /hosts: 112,675 bytes gzip
  • /containers: 117,975 bytes gzip
    No verified pre-change cold-JS values were recorded in this issue or the saved artifact logs.

The browser run refreshed all eight screenshots in /mnt/hdd/infraternal/artifacts/ui-datatable/:
light-1440x900-containers.png, light-390x844-containers.png, dark-1440x900-containers.png, dark-390x844-containers.png, light-1440x900-hosts.png, light-390x844-hosts.png, dark-1440x900-hosts.png, dark-390x844-hosts.png.

Final update after aligning Host filtering with the requested chip controls. Head SHA: 8632a042de8750f1118695f9407c2e69072a827c The branch is clean. The follow-up commit is 8632a04 (fix(web): show host filter chips); it also verifies host chip selection and reset in the browser flow. Final verification: - UI tests: 3 files and 10 tests passed. - Web: svelte-check found 0 errors and 0 warnings; 13 files and 69 tests passed. - Focused real-browser flow: PASS focused DataTable browser: light/dark desktop/mobile screenshots, sort, keyboard navigation, three-row selection, bulk Stop plan/confirmation/execute - Fast gate output excerpt, verbatim: PASS fast: build web app (13.320s) PASS fast: cargo fmt --check (1.554s) FAIL fast: cargo clippy (6.371s) Clippy reports nine assert_is_empty lints in untouched engine/proto tests: six in crates/engine/tests/integration.rs and three in crates/proto/src/stream/controls.rs and crates/proto/src/stream/records.rs. Final cold route JS: - /hosts: 112,675 bytes gzip - /containers: 117,975 bytes gzip No verified pre-change cold-JS values were recorded in this issue or the saved artifact logs. The browser run refreshed all eight screenshots in /mnt/hdd/infraternal/artifacts/ui-datatable/: light-1440x900-containers.png, light-390x844-containers.png, dark-1440x900-containers.png, dark-390x844-containers.png, light-1440x900-hosts.png, light-390x844-hosts.png, dark-1440x900-hosts.png, dark-390x844-hosts.png.
Author
Owner

The latest release-browser run reached the UI and stream matrix. It passed the bfcache/stream lifecycle stress check (SPA transitions=50 reloads=20, zero live sockets and zero post-close DATA), terminal DATA/CREDIT accounting, and route JS gzip measurements. It failed after 621.643s with an uncaught Playwright Route is already handled! from the held stream-ticket route, then timed out after 30s waiting for the Container logs heading in captureDynamicRouteMatrix. I am updating route teardown to wait for in-flight handlers and adding route-specific readiness diagnostics; I will rerun under lower contention.

The latest release-browser run reached the UI and stream matrix. It passed the bfcache/stream lifecycle stress check (`SPA transitions=50 reloads=20`, zero live sockets and zero post-close DATA), terminal DATA/CREDIT accounting, and route JS gzip measurements. It failed after 621.643s with an uncaught Playwright `Route is already handled!` from the held stream-ticket route, then timed out after 30s waiting for the Container logs heading in `captureDynamicRouteMatrix`. I am updating route teardown to wait for in-flight handlers and adding route-specific readiness diagnostics; I will rerun under lower contention.
Author
Owner

Final head f47f6b2: 30 consecutive loaded production multi-tab repetitions completed with exit 0. Supported=30 (each exactly ONE refresh across all three active pages); sign-out=30; locks-only=30; neither=30; total 120 checks. Native supported-mode timers and coordination remain active. Fallback clocks are isolated and initial real authorization responses are observed before another tab rotates. Eight stress-ng CPU workers stayed active throughout and were stopped/reaped before fast verification.

Actual browser output:

PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=1/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=2/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=3/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=4/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=5/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=6/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=7/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=8/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=9/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=10/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=11/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=12/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=13/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=14/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=15/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=16/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=17/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=18/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=19/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=20/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=21/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=22/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=23/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=24/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=25/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=26/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=27/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=28/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=29/30
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
PASS multi-tab repetition=30/30

Actual load output:

stress-ng: info:  [1445830] defaulting to a 1 day run per stressor
stress-ng: info:  [1445830] dispatching hogs: 8 cpu
stress-ng: info:  [1445830] skipped: 0
stress-ng: info:  [1445830] passed: 8: cpu (8)
stress-ng: info:  [1445830] failed: 0
stress-ng: info:  [1445830] metrics untrustworthy: 0
stress-ng: info:  [1445830] successful run completed in 5 mins, 57.38 secs

Raw stress log: /home/kayg/.cache/infraternal-targets/multitab-refresh/multitab-stress.log. Screenshot artifacts: /mnt/hdd/infraternal/artifacts/verify/multitab-refresh-stress/browser/ (supported, locks-only, neither at 1440×900 and 390×844). Required INFRATERNAL_VERIFY_RUN_ID=multitab-refresh scripts/verify fast is now running, with the previously documented RUSTC_WRAPPER= and CARGO_INCREMENTAL=0 environment workaround. No Rust source changes; no performance-budget claim from this CPU-loaded VM test.

Final head f47f6b2: 30 consecutive loaded production multi-tab repetitions completed with exit 0. Supported=30 (each exactly ONE refresh across all three active pages); sign-out=30; locks-only=30; neither=30; total 120 checks. Native supported-mode timers and coordination remain active. Fallback clocks are isolated and initial real authorization responses are observed before another tab rotates. Eight stress-ng CPU workers stayed active throughout and were stopped/reaped before fast verification. Actual browser output: ```text PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=1/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=2/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=3/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=4/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=5/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=6/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=7/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=8/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=9/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=10/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=11/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=12/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=13/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=14/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=15/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=16/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=17/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=18/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=19/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=20/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=21/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=22/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=23/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=24/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=25/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=26/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=27/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=28/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=29/30 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery PASS multi-tab neither: one notice per tab and sequential stale-access recovery PASS multi-tab repetition=30/30 ``` Actual load output: ```text stress-ng: info: [1445830] defaulting to a 1 day run per stressor stress-ng: info: [1445830] dispatching hogs: 8 cpu stress-ng: info: [1445830] skipped: 0 stress-ng: info: [1445830] passed: 8: cpu (8) stress-ng: info: [1445830] failed: 0 stress-ng: info: [1445830] metrics untrustworthy: 0 stress-ng: info: [1445830] successful run completed in 5 mins, 57.38 secs ``` Raw stress log: /home/kayg/.cache/infraternal-targets/multitab-refresh/multitab-stress.log. Screenshot artifacts: /mnt/hdd/infraternal/artifacts/verify/multitab-refresh-stress/browser/ (supported, locks-only, neither at 1440×900 and 390×844). Required INFRATERNAL_VERIFY_RUN_ID=multitab-refresh scripts/verify fast is now running, with the previously documented RUSTC_WRAPPER= and CARGO_INCREMENTAL=0 environment workaround. No Rust source changes; no performance-budget claim from this CPU-loaded VM test.
Author
Owner

Finished multitab-refresh. Branch: multitab-refresh. Head: e650051149. No push; issues remain open.

Root cause: the product ignored session broadcasts in already signed-in tabs without a pending refresh, leaving revoked access credentials to start another rotation on polling 401s. Comparing the refresh baseline against the maximum stored generation also hid a completed rotation whose broadcast was still queued. Generation-wait timeout/sign-out could fall through to another refresh. The fix adopts successor credentials in signed-in tabs, compares against the generation of the held access credential, and fences waits/async completion against sign-out; observing a newer stored generation never falls through to another rotation.

Browser fixture races also existed: the fixed delay did not establish real lock contention, the existing signed-in tab's refreshes were uncounted, and unsupported-mode tabs could poll concurrently during supposedly sequential recovery. Supported-mode now waits for native held/pending refresh locks and successful use of the same credential by all three active tabs, and counts every context refresh. Unsupported-mode uses a context-wide paused browser clock and drains real requests between sequential operations. Exactly-one refresh assertion is unchanged.

Validation: 18 auth Vitest cases pass; four new product regressions failed against the original implementation. Production release browser stress passed 30 consecutive repetitions with stress-ng --cpu 8: supported=30, sign-out=30, locks-only=30, neither=30; every supported repetition issued exactly ONE refresh. Workers and test server were stopped. Stress was on f47f6b2b5b; its auth/test/browser files are byte-identical to this head. Final head merges origin/dev 411c758's already-landed Rust 1.99 lint fixes; no additional backend changes were authored here.

Final fast command: RUSTC_WRAPPER= CARGO_INCREMENTAL=0 INFRATERNAL_VERIFY_RUN_ID=multitab-refresh scripts/verify fast. Exit 0. The wrapper override avoids this VM's sccache incremental-compilation rejection. Full output quoted verbatim:

WARN load5=18.84 exceeds online CPU count=8; timing-sensitive checks may be delayed
PASS fast: migrations are append-only (0.320s)
PASS fast: workspace package dependencies (0.853s)
PASS fast: JavaScript dependencies (0.290s)
PASS fast: advisory review policy tests (0.264s)
SUPPLY_CHAIN_REVIEWS advisory exceptions are within their review windows
SUPPLY_CHAIN cargo-deny: cargo-deny 0.20.2
SUPPLY_CHAIN_NOTICES generated THIRD_PARTY_NOTICES.md from 95 frontend packages
SUPPLY_CHAIN_NOTICES copied source: 179 shadcn files, 3 calternal-derived files
SUPPLY_CHAIN_NOTICES license files: 66 distinct texts; 0 packages need manual license review
advisories ok
SUPPLY_CHAIN_RUST_ADVISORIES passed with refreshed advisory data
licenses ok
SUPPLY_CHAIN_RUST_LICENSES passed
bun audit v1.4.2 (744846f84)

cookie@0.6.0
  workspace:@infraternal/web > @sveltejs/kit > cookie
  low: cookie accepts cookie name, path, and domain with out of bounds characters (<0.7.0) - https://github.com/advisories/GHSA-pxg6-pf52-xh8x

1 vulnerability (1 low)

  bun audit fix           upgrade the vulnerable packages within their ranges
  bun audit fix --latest  also cross major versions
SUPPLY_CHAIN_BUN_AUDIT findings reported; this check is report-only
SUPPLY_CHAIN_PASS Rust advisory/license checks complete; Bun findings are report-only
PASS fast: supply-chain checks (9.381s)
PASS fast: build web app (20.148s)
PASS fast: cargo fmt --check (2.245s)
PASS fast: cargo clippy (46.373s)
PASS fast: cargo test (376.272s)
PASS fast: svelte-check (22.736s)
PASS fast: UI package svelte-check (6.475s)
PASS fast: stream package typecheck (5.652s)
PASS fast: Vitest (7.242s)
PASS fast: UI package Vitest (25.483s)
PASS fast: stream package Vitest (1.338s)
PASS fast: OpenAPI and TypeScript client drift (60.459s)
PASS fast: terminal TypeScript (2.656s)
PASS fast: terminal Vitest (1.432s)

Production browser stress output quoted verbatim:

AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401
AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-3 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-3 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-4 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-4 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FPZAX9MR4812Z6XQGTGD6
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FQ1G5D64SPCA1GZTSRCYA
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FQ3QNJC2QEGZ9NVSRANV9
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FQ5B5KB8CRNBWHK7A37HY
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=1/30
AUTH_REFRESH context=main page=main-page-6 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-6 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-7 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-7 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FQCVQ4R44V0FHR8NDX8QJ
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FQDYFK9DWJJV58TDEDM8E
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FQH2P6HPRA7CQRP5TGHVK
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FQJX4JRED7TVA3YEJPSTA
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=2/30
AUTH_REFRESH context=main page=main-page-8 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-8 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-10 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-10 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FQSFH0XXP5E8HNXY8N6SJ
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FQV1G4DPWQBFJVXFWNBAE
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FQZ0N0K4P5HEE2VWCS794
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FR2WFHVFX1692J3NA9B7Q
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=3/30
AUTH_REFRESH context=main page=main-page-12 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-12 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-13 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-13 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FRJV0YHC6RZY3F9K9J067
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FRPD2F431G2VDZ2THEW08
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FRV1CE1AYBABKNZ5HMQMZ
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FRX3C87XK0V9PA95M25S1
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=4/30
AUTH_REFRESH context=main page=main-page-14 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-14 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-16 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-16 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FS40NBAF0DE0N3ACSQR45
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FS52EG7JBGV7JRCTSH0BN
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FS76PE2TZSNQRKBJQF6TD
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FS8W1VH90Q6GQSE3TJYDV
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=5/30
AUTH_REFRESH context=main page=main-page-18 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-18 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-19 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-19 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FSEPQZG320Z16NJNXKH6A
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FSFKS8F628RC2ZHKCG2Q4
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FSH1XAP5A453S03R123XF
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FSHX5X7KR7NXMSEW662RV
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=6/30
AUTH_REFRESH context=main page=main-page-21 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-21 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-22 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-22 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FSPKNVHBH4J1FZQQJS5JM
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FSQB80V374TW3RMZBR135
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FSRYXF8N0GY22YGRQSWJK
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FST0H1A93HWCWWKE4CR8X
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=7/30
AUTH_REFRESH context=main page=main-page-24 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-24 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-25 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-25 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FSZETY3HSKTG3DXZAA8YE
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FT0JEK3WBYQQPW8DAP0H6
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FT3A04ZK62ZC3PHY2GTT3
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FT4CRGMJKF9QAXT3HDB25
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=8/30
AUTH_REFRESH context=main page=main-page-26 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-26 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-28 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-28 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FTAYY6SSJ9B9D4JT0437B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FTCDFX5NB7CTMSGKDCN85
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FTEF42Y92Y657YP80NCAW
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FTFVVZEZKJ2CPGZ4GETEC
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=9/30
AUTH_REFRESH context=main page=main-page-30 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-30 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-31 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-31 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FTPJZAFENEQY3A1KKX4V9
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FTQKS5J6GA574E3CABX5Z
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FTS6YQDFZMFKV66W8XK87
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FTT0PVJQ4KPPV9PD12WRC
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=10/30
AUTH_REFRESH context=main page=main-page-32 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-32 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-34 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-34 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FTZJ509STGZ9348XA2XAS
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FV0D84NE8DVG2QXHPH712
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FV1WPRT22FW37Q1QSFHNP
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FV2Q0FSXJ3P6ZMTAH2RAQ
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=11/30
AUTH_REFRESH context=main page=main-page-36 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-36 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-37 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-37 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FV86FK2G29V70DGJFSVD3
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FV90KGFWGKEJ12863RSPQ
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FVAA08X4SX48JKQTF5P18
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FVB2A2AGNE5JZ3N1WXXVH
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=12/30
AUTH_REFRESH context=main page=main-page-39 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-39 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-40 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-40 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FVFTDNQ8QGS7T004P9S98
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FVGJEZ9EWN614QJDMEN8A
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FVJGEQ3HPBET86231QZ22
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FVKH6HJGJ16F34D2YNVH2
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=13/30
AUTH_REFRESH context=main page=main-page-41 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-41 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-43 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-43 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FVSCZ15K2C1R0ZJFX7WZ5
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FVTDQXVEGB7PHDWSWDGBC
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FVW22700ZDWPCP2SZDWP8
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FVWZ9Y0BN1B6783S0XDDV
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=14/30
AUTH_REFRESH context=main page=main-page-44 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-44 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-46 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-46 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FW39Q54KRVKF488W222M3
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FW4ABTC3D4C5X4KK9N15Y
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FW66V0VABSX1RFPHMR74E
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FW7EAYVYP4SW7DSFTZXTQ
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=15/30
AUTH_REFRESH context=main page=main-page-47 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-47 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-49 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-49 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FWCVHVPP9RK4QBV7GRY35
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FWE3PKQTSJ9HGEH027M36
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FWGBEEY3SSE3HD6B6Q9N8
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FWH9AA83BB7RNJREC8YZQ
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=16/30
AUTH_REFRESH context=main page=main-page-51 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-51 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-52 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-52 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FWQ6BMVCX0EJ5E5DY1JKX
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FWR6HYCCNG22J6G4W5YQG
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FWT6VAW1G7G9SYKPH89NE
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FWVJ2T0C8TNNH3SJTJSDJ
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=17/30
AUTH_REFRESH context=main page=main-page-53 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-53 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-55 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-55 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FX133JQBKFRTTC9BP2REV
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FX26HK72QJB3KWD0T3VYC
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FX4D9VRN2AD2CCKCQJ2YK
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FX5N8CXP227EK0VKT89W7
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=18/30
AUTH_REFRESH context=main page=main-page-56 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-56 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-58 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-58 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FXC3BDFAR3Q96ZPKCSR8P
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FXDD9MW3PVJYZK0NRFH0R
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FXFQTPF41T5F3QF27BWTV
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FXHXRQFZDVJQVYP2DXYA2
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=19/30
AUTH_REFRESH context=main page=main-page-60 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-60 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-61 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-61 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FXRTT4GEHYDSFZ65KYR0Q
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FXTPT4BT7BZXA4200C1TR
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FXX3EBRFPG42K5E40TN2J
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FXYERAWJCKRXZ6DEF6MSQ
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=20/30
AUTH_REFRESH context=main page=main-page-63 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-63 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-64 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-64 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FY444CPPX8V6MYWRV6W1Z
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FY54N759MN837ZMS29SK3
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FY895PNMG19XHPCY44RQV
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FYB25NVV78X31WMCNDGQP
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=21/30
AUTH_REFRESH context=main page=main-page-66 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-66 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-67 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-67 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FYNFPE4A49MTC847X8QVQ
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FYQHTXTYQMCB2RWZRKJ71
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FYT2EXA961WZ3GR96MJ2A
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FYTZTYTPW9V4FBKCTCTVE
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=22/30
AUTH_REFRESH context=main page=main-page-69 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-69 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-70 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-70 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FZ0VHAZ035DA51J4HCS6X
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FZ1VZT8BGXE8J186E64NH
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FZ3TAB3CVN28N11163VZ3
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FZ4YE2G7PCCAQYSZD9YWA
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=23/30
AUTH_REFRESH context=main page=main-page-72 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-72 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-73 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-73 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FZAER7QNA8N40H1CB9KVG
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FZBHREFACPCVY5ZBVN574
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FZD7CRFB4KJDV42PPWXSE
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FZEA2RJ812J4JH8SJM3M3
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=24/30
AUTH_REFRESH context=main page=main-page-74 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-74 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-76 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-76 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FZMDDHP06VP6GNNY96XHX
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FZNB04P3A2C8R9HJ45VAM
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FZQ00GR0QTKGSPXRAR6YT
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FZR3GVZRX9KPZAR9E2DCR
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=25/30
AUTH_REFRESH context=main page=main-page-78 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-78 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-79 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-79 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FZX3DGF08H4RZ9NCRTJB3
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FZXXVP20M1MWWNDT024F6
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FZZY68P8C6F1PYHWZ0KY6
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41G011PNK4TT8H5HZWNGQFC
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=26/30
AUTH_REFRESH context=main page=main-page-81 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-81 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-82 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-82 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41G06HR333WY798YF3DYVX0
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41G07G5GFA84XZFQW32ZBB5
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41G09EAS3RAW2VS3V4QCMDT
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41G0AE172CJPGRJT00CYMV4
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=27/30
AUTH_REFRESH context=main page=main-page-84 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-84 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-85 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-85 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41G0GEPBHT9AXHW7SJHW8VM
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41G0HPP3MVMPP26JHCM6HM4
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41G0KJ3QVZ5Y5EVQEGTTF62
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41G0MSVJZNSHSY6GZ6GKKC0
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=28/30
AUTH_REFRESH context=main page=main-page-87 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-87 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-88 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-88 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41G0YS2QFQ87H5VPVT2WKRD
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41G0ZXAVSG2V60HY7N6RR04
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41G12T4KKZJ415ZHFBWBJGC
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41G140F3Q8RBXG1S17MWPBF
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=29/30
AUTH_REFRESH context=main page=main-page-89 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-89 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
AUTH_REFRESH context=main page=main-page-91 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request
AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200
AUTH_REFRESH context=main page=main-page-91 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab sign-out: pending refresh response cannot restore tab B
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41G19YGWXR2AFB9VTRVMWVZ
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41G1B7T8DAQP6CDM7NRAB7Z
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41G1DPY4GXB6SED1HXM8R67
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200
AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41G1F15DR0S0ETME7N6YQ97
PASS multi-tab neither: one notice per tab and sequential stale-access recovery
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request
AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200
PASS multi-tab repetition=30/30

CPU load output quoted verbatim:

stress-ng: info:  [1445830] defaulting to a 1 day run per stressor
stress-ng: info:  [1445830] dispatching hogs: 8 cpu
stress-ng: info:  [1445830] skipped: 0
stress-ng: info:  [1445830] passed: 8: cpu (8)
stress-ng: info:  [1445830] failed: 0
stress-ng: info:  [1445830] metrics untrustworthy: 0
stress-ng: info:  [1445830] successful run completed in 5 mins, 57.38 secs

Artifacts: /mnt/hdd/infraternal/artifacts/verify/multitab-refresh/{fast,stress,stress-ng,auth-regressions,browser}.log. Desktop (1440x900) and mobile (390x844) screenshots: /mnt/hdd/infraternal/artifacts/verify/multitab-refresh-stress/browser/. Inspected signed-in supported desktop/mobile and unsupported mobile notice; no visual source changes.

Applied UI rules: preserve shared primitives/tokens and existing accessible notice/live-region behavior; verify native production browser behavior at desktop/mobile sizes. The change does not add motion or styling.

Mapping to calternal-port: carry over signed-in-or-eligible-pending broadcast adoption, credential-generation baseline, and epoch fences after awaits. Preserve its session_request sharing and BFCache reload logic. Its cold-start historical-generation/250ms-peer timeout must remain distinct from a rotation completed during this recovery; blindly applying the no-fallthrough rule to historical storage would strand cold tabs. Native-lock/shared-cookie regressions apply; adapt new shell locators.

Owner Safari/iOS checklist (no simulator used):

  1. Open two tabs alongside an idle signed-in tab; trigger concurrent stale access recovery and confirm all remain signed in.
  2. Sign out while another tab has refresh pending; confirm it stays signed out.
  3. At phone width, confirm the unsupported-mode notice wraps without clipping.
Finished multitab-refresh. Branch: multitab-refresh. Head: e650051149605fa0ee09ccba037c00d3227bb7cc. No push; issues remain open. Root cause: the product ignored session broadcasts in already signed-in tabs without a pending refresh, leaving revoked access credentials to start another rotation on polling 401s. Comparing the refresh baseline against the maximum stored generation also hid a completed rotation whose broadcast was still queued. Generation-wait timeout/sign-out could fall through to another refresh. The fix adopts successor credentials in signed-in tabs, compares against the generation of the held access credential, and fences waits/async completion against sign-out; observing a newer stored generation never falls through to another rotation. Browser fixture races also existed: the fixed delay did not establish real lock contention, the existing signed-in tab's refreshes were uncounted, and unsupported-mode tabs could poll concurrently during supposedly sequential recovery. Supported-mode now waits for native held/pending refresh locks and successful use of the same credential by all three active tabs, and counts every context refresh. Unsupported-mode uses a context-wide paused browser clock and drains real requests between sequential operations. Exactly-one refresh assertion is unchanged. Validation: 18 auth Vitest cases pass; four new product regressions failed against the original implementation. Production release browser stress passed 30 consecutive repetitions with stress-ng --cpu 8: supported=30, sign-out=30, locks-only=30, neither=30; every supported repetition issued exactly ONE refresh. Workers and test server were stopped. Stress was on f47f6b2b5b56f1a225da58748fdf566b32a9d135; its auth/test/browser files are byte-identical to this head. Final head merges origin/dev 411c758's already-landed Rust 1.99 lint fixes; no additional backend changes were authored here. Final fast command: RUSTC_WRAPPER= CARGO_INCREMENTAL=0 INFRATERNAL_VERIFY_RUN_ID=multitab-refresh scripts/verify fast. Exit 0. The wrapper override avoids this VM's sccache incremental-compilation rejection. Full output quoted verbatim: ```text WARN load5=18.84 exceeds online CPU count=8; timing-sensitive checks may be delayed PASS fast: migrations are append-only (0.320s) PASS fast: workspace package dependencies (0.853s) PASS fast: JavaScript dependencies (0.290s) PASS fast: advisory review policy tests (0.264s) SUPPLY_CHAIN_REVIEWS advisory exceptions are within their review windows SUPPLY_CHAIN cargo-deny: cargo-deny 0.20.2 SUPPLY_CHAIN_NOTICES generated THIRD_PARTY_NOTICES.md from 95 frontend packages SUPPLY_CHAIN_NOTICES copied source: 179 shadcn files, 3 calternal-derived files SUPPLY_CHAIN_NOTICES license files: 66 distinct texts; 0 packages need manual license review advisories ok SUPPLY_CHAIN_RUST_ADVISORIES passed with refreshed advisory data licenses ok SUPPLY_CHAIN_RUST_LICENSES passed bun audit v1.4.2 (744846f84) cookie@0.6.0 workspace:@infraternal/web > @sveltejs/kit > cookie low: cookie accepts cookie name, path, and domain with out of bounds characters (<0.7.0) - https://github.com/advisories/GHSA-pxg6-pf52-xh8x 1 vulnerability (1 low) bun audit fix upgrade the vulnerable packages within their ranges bun audit fix --latest also cross major versions SUPPLY_CHAIN_BUN_AUDIT findings reported; this check is report-only SUPPLY_CHAIN_PASS Rust advisory/license checks complete; Bun findings are report-only PASS fast: supply-chain checks (9.381s) PASS fast: build web app (20.148s) PASS fast: cargo fmt --check (2.245s) PASS fast: cargo clippy (46.373s) PASS fast: cargo test (376.272s) PASS fast: svelte-check (22.736s) PASS fast: UI package svelte-check (6.475s) PASS fast: stream package typecheck (5.652s) PASS fast: Vitest (7.242s) PASS fast: UI package Vitest (25.483s) PASS fast: stream package Vitest (1.338s) PASS fast: OpenAPI and TypeScript client drift (60.459s) PASS fast: terminal TypeScript (2.656s) PASS fast: terminal Vitest (1.432s) ``` Production browser stress output quoted verbatim: ```text AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401 AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401 AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401 AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401 AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=http_error status=401 AUTH_401 context=main page=main-page-1 method=POST path=/api/v1/auth/refresh access_token_id=none AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-3 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-3 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-4 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-4 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FPZAX9MR4812Z6XQGTGD6 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FQ1G5D64SPCA1GZTSRCYA AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FQ3QNJC2QEGZ9NVSRANV9 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FQ5B5KB8CRNBWHK7A37HY AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=1/30 AUTH_REFRESH context=main page=main-page-6 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-6 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-7 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-7 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FQCVQ4R44V0FHR8NDX8QJ AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FQDYFK9DWJJV58TDEDM8E AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FQH2P6HPRA7CQRP5TGHVK AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FQJX4JRED7TVA3YEJPSTA PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=2/30 AUTH_REFRESH context=main page=main-page-8 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-8 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-10 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-10 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FQSFH0XXP5E8HNXY8N6SJ AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FQV1G4DPWQBFJVXFWNBAE AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FQZ0N0K4P5HEE2VWCS794 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FR2WFHVFX1692J3NA9B7Q AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=3/30 AUTH_REFRESH context=main page=main-page-12 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-12 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-13 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-13 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FRJV0YHC6RZY3F9K9J067 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FRPD2F431G2VDZ2THEW08 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FRV1CE1AYBABKNZ5HMQMZ AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FRX3C87XK0V9PA95M25S1 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=4/30 AUTH_REFRESH context=main page=main-page-14 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-14 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-16 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-16 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FS40NBAF0DE0N3ACSQR45 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FS52EG7JBGV7JRCTSH0BN AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FS76PE2TZSNQRKBJQF6TD AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FS8W1VH90Q6GQSE3TJYDV AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=5/30 AUTH_REFRESH context=main page=main-page-18 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-18 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-19 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-19 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FSEPQZG320Z16NJNXKH6A AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FSFKS8F628RC2ZHKCG2Q4 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FSH1XAP5A453S03R123XF AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FSHX5X7KR7NXMSEW662RV AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=6/30 AUTH_REFRESH context=main page=main-page-21 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-21 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-22 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-22 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FSPKNVHBH4J1FZQQJS5JM AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FSQB80V374TW3RMZBR135 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FSRYXF8N0GY22YGRQSWJK AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FST0H1A93HWCWWKE4CR8X AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=7/30 AUTH_REFRESH context=main page=main-page-24 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-24 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-25 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-25 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FSZETY3HSKTG3DXZAA8YE AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FT0JEK3WBYQQPW8DAP0H6 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FT3A04ZK62ZC3PHY2GTT3 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FT4CRGMJKF9QAXT3HDB25 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=8/30 AUTH_REFRESH context=main page=main-page-26 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-26 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-28 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-28 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FTAYY6SSJ9B9D4JT0437B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FTCDFX5NB7CTMSGKDCN85 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FTEF42Y92Y657YP80NCAW AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FTFVVZEZKJ2CPGZ4GETEC AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=9/30 AUTH_REFRESH context=main page=main-page-30 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-30 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-31 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-31 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FTPJZAFENEQY3A1KKX4V9 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FTQKS5J6GA574E3CABX5Z AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FTS6YQDFZMFKV66W8XK87 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FTT0PVJQ4KPPV9PD12WRC AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=10/30 AUTH_REFRESH context=main page=main-page-32 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-32 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-34 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-34 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FTZJ509STGZ9348XA2XAS AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FV0D84NE8DVG2QXHPH712 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FV1WPRT22FW37Q1QSFHNP AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FV2Q0FSXJ3P6ZMTAH2RAQ AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=11/30 AUTH_REFRESH context=main page=main-page-36 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-36 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-37 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-37 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FV86FK2G29V70DGJFSVD3 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FV90KGFWGKEJ12863RSPQ AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FVAA08X4SX48JKQTF5P18 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FVB2A2AGNE5JZ3N1WXXVH AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=12/30 AUTH_REFRESH context=main page=main-page-39 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-39 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-40 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-40 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FVFTDNQ8QGS7T004P9S98 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FVGJEZ9EWN614QJDMEN8A AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FVJGEQ3HPBET86231QZ22 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FVKH6HJGJ16F34D2YNVH2 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=13/30 AUTH_REFRESH context=main page=main-page-41 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-41 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-43 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-43 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FVSCZ15K2C1R0ZJFX7WZ5 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FVTDQXVEGB7PHDWSWDGBC AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FVW22700ZDWPCP2SZDWP8 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FVWZ9Y0BN1B6783S0XDDV AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=14/30 AUTH_REFRESH context=main page=main-page-44 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-44 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-46 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-46 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FW39Q54KRVKF488W222M3 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FW4ABTC3D4C5X4KK9N15Y AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FW66V0VABSX1RFPHMR74E AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FW7EAYVYP4SW7DSFTZXTQ AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=15/30 AUTH_REFRESH context=main page=main-page-47 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-47 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-49 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-49 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FWCVHVPP9RK4QBV7GRY35 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FWE3PKQTSJ9HGEH027M36 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FWGBEEY3SSE3HD6B6Q9N8 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FWH9AA83BB7RNJREC8YZQ AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=16/30 AUTH_REFRESH context=main page=main-page-51 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-51 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-52 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-52 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FWQ6BMVCX0EJ5E5DY1JKX AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FWR6HYCCNG22J6G4W5YQG AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FWT6VAW1G7G9SYKPH89NE AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FWVJ2T0C8TNNH3SJTJSDJ AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=17/30 AUTH_REFRESH context=main page=main-page-53 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-53 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-55 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-55 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FX133JQBKFRTTC9BP2REV AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FX26HK72QJB3KWD0T3VYC AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FX4D9VRN2AD2CCKCQJ2YK AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FX5N8CXP227EK0VKT89W7 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=18/30 AUTH_REFRESH context=main page=main-page-56 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-56 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-58 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-58 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FXC3BDFAR3Q96ZPKCSR8P AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FXDD9MW3PVJYZK0NRFH0R AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FXFQTPF41T5F3QF27BWTV AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FXHXRQFZDVJQVYP2DXYA2 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=19/30 AUTH_REFRESH context=main page=main-page-60 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-60 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-61 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-61 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FXRTT4GEHYDSFZ65KYR0Q AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FXTPT4BT7BZXA4200C1TR AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FXX3EBRFPG42K5E40TN2J AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FXYERAWJCKRXZ6DEF6MSQ AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=20/30 AUTH_REFRESH context=main page=main-page-63 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-63 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-64 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-64 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FY444CPPX8V6MYWRV6W1Z AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FY54N759MN837ZMS29SK3 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FY895PNMG19XHPCY44RQV AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FYB25NVV78X31WMCNDGQP AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=21/30 AUTH_REFRESH context=main page=main-page-66 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-66 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-67 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-67 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FYNFPE4A49MTC847X8QVQ AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FYQHTXTYQMCB2RWZRKJ71 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FYT2EXA961WZ3GR96MJ2A AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FYTZTYTPW9V4FBKCTCTVE AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=22/30 AUTH_REFRESH context=main page=main-page-69 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-69 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-70 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-70 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FZ0VHAZ035DA51J4HCS6X AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FZ1VZT8BGXE8J186E64NH AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FZ3TAB3CVN28N11163VZ3 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FZ4YE2G7PCCAQYSZD9YWA AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=23/30 AUTH_REFRESH context=main page=main-page-72 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-72 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-73 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-73 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FZAER7QNA8N40H1CB9KVG AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FZBHREFACPCVY5ZBVN574 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FZD7CRFB4KJDV42PPWXSE AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FZEA2RJ812J4JH8SJM3M3 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=24/30 AUTH_REFRESH context=main page=main-page-74 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-74 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-76 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-76 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FZMDDHP06VP6GNNY96XHX AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FZNB04P3A2C8R9HJ45VAM AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FZQ00GR0QTKGSPXRAR6YT AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FZR3GVZRX9KPZAR9E2DCR AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=25/30 AUTH_REFRESH context=main page=main-page-78 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-78 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-79 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-79 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FZX3DGF08H4RZ9NCRTJB3 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41FZXXVP20M1MWWNDT024F6 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41FZZY68P8C6F1PYHWZ0KY6 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41G011PNK4TT8H5HZWNGQFC AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=26/30 AUTH_REFRESH context=main page=main-page-81 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-81 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-82 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-82 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41G06HR333WY798YF3DYVX0 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41G07G5GFA84XZFQW32ZBB5 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41G09EAS3RAW2VS3V4QCMDT AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41G0AE172CJPGRJT00CYMV4 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=27/30 AUTH_REFRESH context=main page=main-page-84 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-84 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-85 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-85 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41G0GEPBHT9AXHW7SJHW8VM AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41G0HPP3MVMPP26JHCM6HM4 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41G0KJ3QVZ5Y5EVQEGTTF62 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41G0MSVJZNSHSY6GZ6GKKC0 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=28/30 AUTH_REFRESH context=main page=main-page-87 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-87 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-88 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-88 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41G0YS2QFQ87H5VPVT2WKRD AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41G0ZXAVSG2V60HY7N6RR04 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41G12T4KKZJ415ZHFBWBJGC AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41G140F3Q8RBXG1S17MWPBF AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=29/30 AUTH_REFRESH context=main page=main-page-89 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-89 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) AUTH_REFRESH context=main page=main-page-91 method=POST path=/api/v1/auth/refresh outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=request AUTH_SIGNOUT context=main page=main-page-1 method=POST path=/api/v1/auth/signout outcome=success status=200 AUTH_REFRESH context=main page=main-page-91 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab sign-out: pending refresh response cannot restore tab B AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41G19YGWXR2AFB9VTRVMWVZ AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41G1B7T8DAQP6CDM7NRAB7Z AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-locks-only page=multi-tab-locks-only-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab locks-only: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-1 method=GET path=/api/v1/containers access_token_id=t_01M41G1DPY4GXB6SED1HXM8R67 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=multi-tab-neither page=multi-tab-neither-page-2 method=POST path=/api/v1/auth/refresh outcome=success status=200 AUTH_401 context=multi-tab-neither page=multi-tab-neither-page-2 method=GET path=/api/v1/containers access_token_id=t_01M41G1F15DR0S0ETME7N6YQ97 PASS multi-tab neither: one notice per tab and sequential stale-access recovery AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=request AUTH_REFRESH context=main page=main-page-1 method=POST path=/api/v1/auth/refresh outcome=success status=200 PASS multi-tab repetition=30/30 ``` CPU load output quoted verbatim: ```text stress-ng: info: [1445830] defaulting to a 1 day run per stressor stress-ng: info: [1445830] dispatching hogs: 8 cpu stress-ng: info: [1445830] skipped: 0 stress-ng: info: [1445830] passed: 8: cpu (8) stress-ng: info: [1445830] failed: 0 stress-ng: info: [1445830] metrics untrustworthy: 0 stress-ng: info: [1445830] successful run completed in 5 mins, 57.38 secs ``` Artifacts: /mnt/hdd/infraternal/artifacts/verify/multitab-refresh/{fast,stress,stress-ng,auth-regressions,browser}.log. Desktop (1440x900) and mobile (390x844) screenshots: /mnt/hdd/infraternal/artifacts/verify/multitab-refresh-stress/browser/. Inspected signed-in supported desktop/mobile and unsupported mobile notice; no visual source changes. Applied UI rules: preserve shared primitives/tokens and existing accessible notice/live-region behavior; verify native production browser behavior at desktop/mobile sizes. The change does not add motion or styling. Mapping to calternal-port: carry over signed-in-or-eligible-pending broadcast adoption, credential-generation baseline, and epoch fences after awaits. Preserve its session_request sharing and BFCache reload logic. Its cold-start historical-generation/250ms-peer timeout must remain distinct from a rotation completed during this recovery; blindly applying the no-fallthrough rule to historical storage would strand cold tabs. Native-lock/shared-cookie regressions apply; adapt new shell locators. Owner Safari/iOS checklist (no simulator used): 1. Open two tabs alongside an idle signed-in tab; trigger concurrent stale access recovery and confirm all remain signed in. 2. Sign out while another tab has refresh pending; confirm it stays signed out. 3. At phone width, confirm the unsupported-mode notice wraps without clipping.
Author
Owner

Release browser attempt 4 built the release binary and passed the terminal fixture. Playwright reached the bfcache lifecycle stress, then failed because page.evaluate ran immediately after page.goBack({ waitUntil: "commit" }) while the persisted-pageshow reload was destroying that document's execution context. The reload is the expected guard behavior. Updated the browser check to wait for the tracked fresh-document transition before reading persisted lifecycle evidence from sessionStorage. Harness syntax and git diff --check pass; rerunning the release browser gate.

Release browser attempt 4 built the release binary and passed the terminal fixture. Playwright reached the bfcache lifecycle stress, then failed because `page.evaluate` ran immediately after `page.goBack({ waitUntil: "commit" })` while the persisted-pageshow reload was destroying that document's execution context. The reload is the expected guard behavior. Updated the browser check to wait for the tracked fresh-document transition before reading persisted lifecycle evidence from sessionStorage. Harness syntax and `git diff --check` pass; rerunning the release browser gate.
Author
Owner

The fifth release browser run passed the bfcache lifecycle stress and reached the visual route matrix. Its layout assertion found tablet overflow at 768 px on /ai-agent-tokens: the four-column row's revoked status pill extended to x=836.75 while the content edge was x=768. Changed the token list's responsive layout from a viewport breakpoint to a named container query at 36rem, so it stacks when the route content narrows beside the sidebar. Rerunning the release browser gate.

The fifth release browser run passed the bfcache lifecycle stress and reached the visual route matrix. Its layout assertion found tablet overflow at 768 px on `/ai-agent-tokens`: the four-column row's revoked status pill extended to x=836.75 while the content edge was x=768. Changed the token list's responsive layout from a viewport breakpoint to a named container query at 36rem, so it stacks when the route content narrows beside the sidebar. Rerunning the release browser gate.
Author
Owner

The next release browser run passed the bfcache stress and all four theme/viewport route captures, including the 768 px token-list overflow check. It then timed out waiting for the app surface on the C2 page after navigating to /containers in session-pagination setup; #route-content and .auth-screen were both absent for 45 s. Added failure-only diagnostics for document readiness, current URL/title/body, page errors, and failed app document/script requests, then will rerun to determine whether the page boot is failing or transient.

The next release browser run passed the bfcache stress and all four theme/viewport route captures, including the 768 px token-list overflow check. It then timed out waiting for the app surface on the C2 page after navigating to `/containers` in session-pagination setup; `#route-content` and `.auth-screen` were both absent for 45 s. Added failure-only diagnostics for document readiness, current URL/title/body, page errors, and failed app document/script requests, then will rerun to determine whether the page boot is failing or transient.
Author
Owner

The diagnostic rerun did not reproduce the prior blank C2 page; it reached the tablet route assertion and still found the AI-token row overflowing at 768 px. The page query compiled, but the container had no explicit inline size and the grid item's intrinsic minimum could keep the rendered row outside its intended width. Set the route container to inline-size: min(100%, 1120px), allowed its section to shrink, and added failure-only container/grid measurements so another failure reports the actual query container width and computed columns.

The diagnostic rerun did not reproduce the prior blank C2 page; it reached the tablet route assertion and still found the AI-token row overflowing at 768 px. The page query compiled, but the container had no explicit inline size and the grid item's intrinsic minimum could keep the rendered row outside its intended width. Set the route container to `inline-size: min(100%, 1120px)`, allowed its section to shrink, and added failure-only container/grid measurements so another failure reports the actual query container width and computed columns.
Author
Owner

The exact 768 px failure diagnostics show .tokens-page is 411 px wide but computes containerName: none and containerType: normal; the row still has four columns (192px 224px 30.75px 0px). The built stylesheet contains the named container shorthand. MDN documents that shorthand as baseline and supported across browsers since 2023, so this is not an intended unsupported-platform fallback. Switched this route to the same container-type: inline-size longhand pattern used elsewhere in the UI, with an unnamed @container, and added CSS support flags to the failure diagnostic. MDN container property.

The exact 768 px failure diagnostics show `.tokens-page` is 411 px wide but computes `containerName: none` and `containerType: normal`; the row still has four columns (`192px 224px 30.75px 0px`). The built stylesheet contains the named `container` shorthand. MDN documents that shorthand as baseline and supported across browsers since 2023, so this is not an intended unsupported-platform fallback. Switched this route to the same `container-type: inline-size` longhand pattern used elsewhere in the UI, with an unnamed `@container`, and added CSS support flags to the failure diagnostic. [MDN container property](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/container).
Author
Owner

Starting batch3 integration. Branch: batch3. Base head: f0bf5fa. Sole writer; integrating fix-sessions-pty, multitab-refresh, fix-scale-podman, cli-mcp-actions, embedded-list-registry in that order. Clippy after each merge; workspace, real-runtime, SDP audit and fast verification at the end. No push.

Starting batch3 integration. Branch: batch3. Base head: f0bf5fa. Sole writer; integrating fix-sessions-pty, multitab-refresh, fix-scale-podman, cli-mcp-actions, embedded-list-registry in that order. Clippy after each merge; workspace, real-runtime, SDP audit and fast verification at the end. No push.
Author
Owner

Found why the route CSS diagnostics kept reporting the old four-column stylesheet. CARGO_TARGET_DIR is /home/kayg/.cache/infraternal-targets/rs-port; cargo build --release -p infraternal wrote the fresh binary there at 22:06, while scripts/verify launched the stale /home/kayg/wt/calternal-port/target/release/infraternal from 12:13. The gate's server launcher ignored Cargo's configured target directory, so all recent browser attempts were testing a stale release binary. I will make the launcher use the configured target directory (falling back to repo target) and rerun the production browser gate.

Found why the route CSS diagnostics kept reporting the old four-column stylesheet. `CARGO_TARGET_DIR` is `/home/kayg/.cache/infraternal-targets/rs-port`; `cargo build --release -p infraternal` wrote the fresh binary there at 22:06, while `scripts/verify` launched the stale `/home/kayg/wt/calternal-port/target/release/infraternal` from 12:13. The gate's server launcher ignored Cargo's configured target directory, so all recent browser attempts were testing a stale release binary. I will make the launcher use the configured target directory (falling back to repo `target`) and rerun the production browser gate.
Author
Owner

Fast gate passed at 51cb880. Workspace tests, auth Vitest, frontend checks and generated API drift all passed. Full real-service integration now running.

WARN load5=11.31 exceeds online CPU count=8; timing-sensitive checks may be delayed
PASS fast: migrations are append-only (0.149s)
PASS fast: workspace package dependencies (0.303s)
PASS fast: JavaScript dependencies (0.051s)
PASS fast: advisory review policy tests (0.172s)
SUPPLY_CHAIN_REVIEWS advisory exceptions are within their review windows
SUPPLY_CHAIN cargo-deny: cargo-deny 0.20.2
SUPPLY_CHAIN_NOTICES generated THIRD_PARTY_NOTICES.md from 95 frontend packages
SUPPLY_CHAIN_NOTICES copied source: 179 shadcn files, 3 calternal-derived files
SUPPLY_CHAIN_NOTICES license files: 66 distinct texts; 0 packages need manual license review
advisories ok
SUPPLY_CHAIN_RUST_ADVISORIES passed with refreshed advisory data
licenses ok
SUPPLY_CHAIN_RUST_LICENSES passed
bun audit v1.4.2 (744846f84)

cookie@0.6.0
  workspace:@infraternal/web > @sveltejs/kit > cookie
  low: cookie accepts cookie name, path, and domain with out of bounds characters (<0.7.0) - https://github.com/advisories/GHSA-pxg6-pf52-xh8x

1 vulnerability (1 low)

  bun audit fix           upgrade the vulnerable packages within their ranges
  bun audit fix --latest  also cross major versions
SUPPLY_CHAIN_BUN_AUDIT findings reported; this check is report-only
SUPPLY_CHAIN_PASS Rust advisory/license checks complete; Bun findings are report-only
PASS fast: supply-chain checks (4.078s)
PASS fast: build web app (12.332s)
PASS fast: cargo fmt --check (1.221s)
PASS fast: cargo clippy (13.464s)
PASS fast: cargo test (132.804s)
PASS fast: svelte-check (15.774s)
PASS fast: UI package svelte-check (4.663s)
PASS fast: stream package typecheck (4.028s)
PASS fast: Vitest (3.170s)
PASS fast: UI package Vitest (9.980s)
PASS fast: stream package Vitest (0.779s)
PASS fast: OpenAPI and TypeScript client drift (27.981s)
PASS fast: terminal TypeScript (1.780s)
PASS fast: terminal Vitest (1.042s)
Fast gate passed at 51cb880. Workspace tests, auth Vitest, frontend checks and generated API drift all passed. Full real-service integration now running. ```text WARN load5=11.31 exceeds online CPU count=8; timing-sensitive checks may be delayed PASS fast: migrations are append-only (0.149s) PASS fast: workspace package dependencies (0.303s) PASS fast: JavaScript dependencies (0.051s) PASS fast: advisory review policy tests (0.172s) SUPPLY_CHAIN_REVIEWS advisory exceptions are within their review windows SUPPLY_CHAIN cargo-deny: cargo-deny 0.20.2 SUPPLY_CHAIN_NOTICES generated THIRD_PARTY_NOTICES.md from 95 frontend packages SUPPLY_CHAIN_NOTICES copied source: 179 shadcn files, 3 calternal-derived files SUPPLY_CHAIN_NOTICES license files: 66 distinct texts; 0 packages need manual license review advisories ok SUPPLY_CHAIN_RUST_ADVISORIES passed with refreshed advisory data licenses ok SUPPLY_CHAIN_RUST_LICENSES passed bun audit v1.4.2 (744846f84) cookie@0.6.0 workspace:@infraternal/web > @sveltejs/kit > cookie low: cookie accepts cookie name, path, and domain with out of bounds characters (<0.7.0) - https://github.com/advisories/GHSA-pxg6-pf52-xh8x 1 vulnerability (1 low) bun audit fix upgrade the vulnerable packages within their ranges bun audit fix --latest also cross major versions SUPPLY_CHAIN_BUN_AUDIT findings reported; this check is report-only SUPPLY_CHAIN_PASS Rust advisory/license checks complete; Bun findings are report-only PASS fast: supply-chain checks (4.078s) PASS fast: build web app (12.332s) PASS fast: cargo fmt --check (1.221s) PASS fast: cargo clippy (13.464s) PASS fast: cargo test (132.804s) PASS fast: svelte-check (15.774s) PASS fast: UI package svelte-check (4.663s) PASS fast: stream package typecheck (4.028s) PASS fast: Vitest (3.170s) PASS fast: UI package Vitest (9.980s) PASS fast: stream package Vitest (0.779s) PASS fast: OpenAPI and TypeScript client drift (27.981s) PASS fast: terminal TypeScript (1.780s) PASS fast: terminal Vitest (1.042s) ```
Author
Owner

With scripts/verify using the configured cache binary, the fresh production bundle passed the route matrix and exposed the actual mobile focus defect: after opening the Sidebar dialog, focus remained on the opener inside the now-inert app body. Sidebar.svelte had a custom Tab wrap but no initial focus transfer. Wired its mobile dialog to the shared focusTrap primitive, targeting the current route link and delegating Tab containment. It leaves return-focus ownership with close/navigation flows; the explicit close, Escape, and backdrop path returns to the opener, while route and modal transitions can claim focus without a competing restore.

With `scripts/verify` using the configured cache binary, the fresh production bundle passed the route matrix and exposed the actual mobile focus defect: after opening the Sidebar dialog, focus remained on the opener inside the now-inert app body. `Sidebar.svelte` had a custom Tab wrap but no initial focus transfer. Wired its mobile dialog to the shared `focusTrap` primitive, targeting the current route link and delegating Tab containment. It leaves return-focus ownership with close/navigation flows; the explicit close, Escape, and backdrop path returns to the opener, while route and modal transitions can claim focus without a competing restore.
Author
Owner

The first focus-trap change still failed in the production browser: focusTrap activated while the drawer was being made visible, before the browser had cleared its prior inert state. Updated Sidebar's async navigation mount path to recheck after Svelte's tick() and quietly focus the selected route link if focus is still outside. The browser assertion now waits for the real condition dialog.contains(document.activeElement) (5 s cap) before checking Tab containment; no fixed sleep was added.

The first focus-trap change still failed in the production browser: `focusTrap` activated while the drawer was being made visible, before the browser had cleared its prior inert state. Updated Sidebar's async navigation mount path to recheck after Svelte's `tick()` and quietly focus the selected route link if focus is still outside. The browser assertion now waits for the real condition `dialog.contains(document.activeElement)` (5 s cap) before checking Tab containment; no fixed sleep was added.
Author
Owner

The mobile drawer focus fix passed. The next browser failure was a contaminated sidebar fixture: desktop/tablet checks had already created the default Access/Admin groups and custom groups in the shared browser account, while the mobile touch case asserted a fresh single-Infrastructure state. It now resets the persisted arrangement before measuring, verifies the canonical infrastructure/access/admin baseline, then drags the existing Access group.

The mobile drawer focus fix passed. The next browser failure was a contaminated sidebar fixture: desktop/tablet checks had already created the default Access/Admin groups and custom groups in the shared browser account, while the mobile touch case asserted a fresh single-Infrastructure state. It now resets the persisted arrangement before measuring, verifies the canonical `infrastructure/access/admin` baseline, then drags the existing Access group.
Author
Owner

Browser attempt 12 reached the sidebar keyboard sorting check and failed:

Expected: "Hosts moved to Infrastructure, position 2 of 2."
Received: "Hosts moved to Access, position 1 of 2."

The test had not established the default expanded Infra list before issuing ArrowDown. checkKeyboardPaths now calls the existing reset action and verifies the default ["hosts", "containers"] order and visible Hosts handle before the move. The assertion and product budgets remain unchanged. I am rerunning the release browser gate.

Browser attempt 12 reached the sidebar keyboard sorting check and failed: `Expected: "Hosts moved to Infrastructure, position 2 of 2."` `Received: "Hosts moved to Access, position 1 of 2."` The test had not established the default expanded Infra list before issuing ArrowDown. `checkKeyboardPaths` now calls the existing reset action and verifies the default `["hosts", "containers"]` order and visible Hosts handle before the move. The assertion and product budgets remain unchanged. I am rerunning the release browser gate.
Author
Owner

Browser attempt 13 passed release build, authentication/multi-tab checks, and sidebar persistence (including the default keyboard-sort fixture), then failed in checkLogControls at the ArrowUp scroll assertion. After the 5 s poll, scrollTop was 10,520 while the captured starting value was 10,500. The VM load was 12.03 / 9.95 / 8.70; scripts/verify integration and scripts/verify merge were active concurrently. No product budget or assertion was changed. I will rerun the browser gate after that load clears before investigating the scroll behavior.

Browser attempt 13 passed release build, authentication/multi-tab checks, and sidebar persistence (including the default keyboard-sort fixture), then failed in `checkLogControls` at the ArrowUp scroll assertion. After the 5 s poll, `scrollTop` was 10,520 while the captured starting value was 10,500. The VM load was 12.03 / 9.95 / 8.70; `scripts/verify integration` and `scripts/verify merge` were active concurrently. No product budget or assertion was changed. I will rerun the browser gate after that load clears before investigating the scroll behavior.
Author
Owner

Browser attempt 14 repeated the checkLogControls ArrowUp failure after the integration and merge verification processes had cleared: scrollTop was 7,820 after 5 s, versus 7,800 before the keypress. The fixture is still streaming log rows every 100 ms. VirtualLogList virtualizes rows and pauses follow on ArrowUp; the check currently compares absolute scrollTop, which can change as streamed rows are measured. I am changing this assertion to verify that the visible row moves upward and the “Jump to latest” control appears, while keeping the timeout and all product budgets unchanged.

Browser attempt 14 repeated the `checkLogControls` ArrowUp failure after the integration and merge verification processes had cleared: `scrollTop` was 7,820 after 5 s, versus 7,800 before the keypress. The fixture is still streaming log rows every 100 ms. `VirtualLogList` virtualizes rows and pauses follow on ArrowUp; the check currently compares absolute `scrollTop`, which can change as streamed rows are measured. I am changing this assertion to verify that the visible row moves upward and the “Jump to latest” control appears, while keeping the timeout and all product budgets unchanged.
Author
Owner

Browser attempt 15 passed the log-control check and the desktop/tablet route matrix, then failed during the mobile touch reorder check. Playwright strict mode found two .nav-group[data-drop-group="access"] elements: the live group and dnd-kit's hidden drag placeholder. The mobile fixture already filters placeholders when measuring order; I am applying the same exclusion to the group locator used by its drag assertion.

Browser attempt 15 passed the log-control check and the desktop/tablet route matrix, then failed during the mobile touch reorder check. Playwright strict mode found two `.nav-group[data-drop-group="access"]` elements: the live group and dnd-kit's hidden drag placeholder. The mobile fixture already filters placeholders when measuring order; I am applying the same exclusion to the group locator used by its drag assertion.
Author
Owner

Browser attempt 16 passed log controls, the mobile group reorder, the route screenshots, and the persisted-page stream lifecycle checks. It then timed out waiting for the Open terminal action after openContainerDetails had waited only for the static Container logs heading. I am making that helper wait for the loaded container title, and adding page-state diagnostics if the action is still absent.

Browser attempt 16 passed log controls, the mobile group reorder, the route screenshots, and the persisted-page stream lifecycle checks. It then timed out waiting for the `Open terminal` action after `openContainerDetails` had waited only for the static `Container logs` heading. I am making that helper wait for the loaded container title, and adding page-state diagnostics if the action is still absent.
Author
Owner

Batch3 integration complete

Head: 66b4eafe5b. Branch: batch3. Base: f0bf5fa. No push; issues remain open.

Branch Incoming head Merge commit Clippy after merge
fix-sessions-pty c509e6f c5a833e PASS
multitab-refresh e650051 5c461a2 PASS
fix-scale-podman 3cff6e4 d7d1d05 PASS
cli-mcp-actions 1f2dac9 acb0e9e PASS
embedded-list-registry 2a627b8 638706d PASS

Batch3 integration conflict notes

  1. fix-sessions-pty: e2e/remote/README.md and operations.ts conflicted. Retained SSH changed-key/revocation and scope-denial rows/imports; added persistent DELETE row and CLI PTY import. First Clippy attempts blocked by sccache incremental policy and missing embedded bundle; disabled wrapper and built locked web dependencies.

  2. multitab-refresh: clean textual merge; auth implementation, Vitest tests, browser-check and verify changes retained. Clippy passed.

  3. fix-scale-podman: eight conflicts, all overlapping Rust 1.99 empty-value assertions already fixed differently on dev. Kept dev typed-empty-array assertions and existing security regression additions; preserved bounded collector, independent Podman discovery, coalesced invalidations and true resync-gap semantics.

  4. cli-mcp-actions: six conflicted files. Kept dev assertion fixes, added the incoming server-tail/follow regression, and used the incoming tested MSRV-compatible atomic compare-exchange helper at both admission sites. Removed superseded deprecation comments/allowances. Retained scale event semantics and existing security tests.

  5. embedded-list-registry: resolved 24 conflicted paths, including facade modify/delete conflicts. Removed the engine facade and server LocalInventory; moved the bounded event-batch primitive plus four regressions to crates/agent/src/provider_runtime/event_batch.rs. Kept scale ordinary invalidation vs true gap semantics, while forwarding each compact notice into the new bounded runtime ring. Native actor-less events now invalidate normally instead of fabricating a gap. Retained the new event normalization and adapted the existing secret-redaction regression to the provider envelope. Kept remote SSH directives, ownership, identity-stop deadlines, tunnel controls, confirmed/absent DELETE acknowledgements, CLI tail/follow tests, and dev assertion fixes. Adapted security sweep fixtures to LocalHost + HostRouter. Removed legacy RemoteInventory-only tests with that removed path; registry tests/real audit check cover the replacement. Preserved native collector table, updated provider and remote SSH contract text. Clippy caught duplicate imports and stale API/facade references; fixed them without restoring the old path.

Integration fixes beyond the merges:

  • 51cb880: compact-ring test admits two ordinary notices before injecting actual overflow.
  • 1939d36: real stream fixtures wait for exact inventory readiness before OPEN or dispatch failure injection; authorization and cleanup deadlines stay unchanged.
  • ca3d71d: failed/incomplete bounded scans retry after one second on the same native feed, including idle initial and post-resync failure. Healthy feeds do not poll or construct a timer. Seventeen provider-runtime tests and thirteen real stream regressions pass. docs/contracts.md records the policy.
  • 714fa1e: HTTP readiness helper retains typed ApiError responses, allowing the existing 200/503 readiness polling to run without decoding an error as a container list.
  • 66b4eaf: serialize real-client scenarios and isolate their temporary credential config paths; four combined CLI/MCP tests pass in one process.

Validation on final head:

  • Required INFRATERNAL_VERIFY_RUN_ID=batch3 scripts/verify fast: PASS. Cargo fmt, Clippy, workspace tests, frontend typechecks, auth Vitest, generated OpenAPI/TypeScript-client drift and terminal checks pass.
  • scripts/verify integration: PASS on 66b4eaf.
  • scripts/verify merge: PASS on 66b4eaf.
  • Full e2e-remote parity: 60/60 PASS, 0 expected failures, cleanup_errors=[].
  • SDP audit: 13/13 PASS, cleanup completed. Both embedded and enrolled remote Docker/Podman paths; server-applied tail+follow; successful DELETE confirms native shell is gone and attached stream closes; DOCKER_HOST points to Docker while Podman stays independent; all 305 exact native IDs appear through both APIs and compiled CLIs for each engine.

Parity and SDP evidence used ca3d71d production code. Diff ca3d71d..66b4eaf changes only crates/server/tests/resources_http.rs and crates/infraternal/tests/cli_mcp.rs, so the production code is identical.

Additional real tests: provider-podman/real 3 PASS (rootful, rootless, DOCKER_HOST isolation); provider-docker/real 1 PASS; provider_real 2 PASS (signed parity/reconnect and 305-container remote-runtime burst); real_sshd 15 PASS; ssh_product 4 PASS; agent_tunnel with Docker+liveness 1 PASS; remote_ssh 1 PASS.

Evidence:

  • Gate logs and additional test logs: /mnt/hdd/infraternal/artifacts/verify/batch3/.
  • SDP runner and JSON: /mnt/hdd/infraternal/artifacts/verify/batch3/audit-final/.
  • Parity report: /mnt/hdd/infraternal/artifacts/verify/batch3-parity-recovery/e2e/remote-batch3-parity-recovery/report.json.
  • Final-head browser screenshots: /mnt/hdd/infraternal/artifacts/verify/batch3-merge-final-head/browser/ (desktop and 390×844).

Failed runs are retained in batch3-integration, batch3-integration-final, batch3-integration-recovery, batch3-integration-complete and batch3-remote artifact directories. They exposed startup-readiness races, idle-feed scan recovery, and test-fixture collisions corrected above. An embedded Podman inventory deadline and a persistent SSH replay exit deadline did not recur in targeted or full rechecks; their precise causes were not proven, and no deadlines or expected-failure policy were relaxed. Successful CLI schema validation prints caught alternate-schema assertion panics; its actual test result is 4 passed, 0 failed.

Measurements here are dev-VM diagnostics, not a new performance-VM A/B certification. Existing low cookie advisory remains report-only under repository policy. All commits carry the requested trailers. No generated caches, benchmark data, credentials or secrets were committed.

Working tree is clean; the temporary target symlink was removed. All five incoming heads are ancestors of HEAD; all ten first-parent integration commits have the requested trailers. No push and no issues closed.

Successful per-merge Clippy output tails (command: RUSTC_WRAPPER= CARGO_INCREMENTAL=0 cargo clippy --workspace --all-targets -- -D warnings):

fix-sessions-pty:

    Finished `dev` profile [unoptimized] target(s) in 30.91s

multitab-refresh:

    Finished `dev` profile [unoptimized] target(s) in 0.50s

fix-scale-podman:

    Finished `dev` profile [unoptimized] target(s) in 30.36s

cli-mcp-actions:

    Finished `dev` profile [unoptimized] target(s) in 28.41s

embedded-list-registry:

    Finished `dev` profile [unoptimized] target(s) in 0.90s

Required fast gate, output excerpt quoted verbatim:

PASS fast: migrations are append-only (0.183s)
PASS fast: workspace package dependencies (0.250s)
PASS fast: JavaScript dependencies (0.008s)
PASS fast: advisory review policy tests (0.148s)
PASS fast: supply-chain checks (3.638s)
PASS fast: build web app (12.021s)
PASS fast: cargo fmt --check (1.330s)
PASS fast: cargo clippy (9.893s)
PASS fast: cargo test (125.899s)
PASS fast: svelte-check (11.027s)
PASS fast: UI package svelte-check (6.179s)
PASS fast: stream package typecheck (4.224s)
PASS fast: Vitest (3.813s)
PASS fast: UI package Vitest (12.130s)
PASS fast: stream package Vitest (1.283s)
PASS fast: OpenAPI and TypeScript client drift (28.547s)
PASS fast: terminal TypeScript (3.611s)
PASS fast: terminal Vitest (1.734s)

Full integration gate, output excerpt quoted verbatim:

PASS integration: JavaScript dependencies (0.004s)
PASS integration: build web app (11.925s)
PASS integration: build release binary (357.443s)
PASS integration: real HTTP behavior (0.614s)
PASS integration: Docker socket _ping (0.013s)
PASS integration: rootless Podman socket _ping (0.012s)
PASS integration: engine adapters against Docker and Podman (242.678s)
PASS integration: bounded follow:false log snapshots against Docker and rootless Podman (12.838s)
PASS integration: TypeScript stream client against Docker and Podman (21.608s)
PASS integration: stream authorization and CLOSE regressions against Docker (90.307s)
PASS integration: persistent PTY termination preempts blocked send (1.621s)
PASS integration: resource HTTP API against Docker and rootless Podman (35.306s)
PASS integration: compiled CLI and MCP against real server and engines (130.818s)
PASS integration: SSH contract against isolated real sshd (14.658s)
PASS integration: SSH product API and stream against isolated real sshd (16.169s)
PASS integration: remote mTLS infraternal agent enroll, rotate, list, exec and revoke against Docker (23.978s)
PASS integration: remote SSH through the mTLS tunnel against isolated real sshd (4.103s)

Merge gate, output excerpt quoted verbatim:

PASS merge: build release binary (306.344s)
PASS merge: release server HTTP and static behavior (0.467s)
PASS merge: Docker socket _ping (0.009s)
PASS merge: rootless Podman socket _ping (0.009s)
PASS merge: Docker exec PTY smoke (1.129s)
PASS merge: rootless Podman inventory and lifecycle smoke (3.289s)
PASS merge: real sshd session ownership smoke (0.850s)
PASS merge: persistent-session authorization-loss security smoke (1.889s)
PASS merge: install Chromium and system dependencies (2.936s)
PASS merge: production browser smoke (10.512s)

Browser evidence inspected at both sizes: desktop, 390×844.

Batch3 integration complete Head: 66b4eafe5bc7cc13d0b57570708dd762a3d01da0. Branch: batch3. Base: f0bf5fa. No push; issues remain open. | Branch | Incoming head | Merge commit | Clippy after merge | | --- | --- | --- | --- | | fix-sessions-pty | c509e6f | c5a833e | PASS | | multitab-refresh | e650051 | 5c461a2 | PASS | | fix-scale-podman | 3cff6e4 | d7d1d05 | PASS | | cli-mcp-actions | 1f2dac9 | acb0e9e | PASS | | embedded-list-registry | 2a627b8 | 638706d | PASS | Batch3 integration conflict notes 1. fix-sessions-pty: e2e/remote/README.md and operations.ts conflicted. Retained SSH changed-key/revocation and scope-denial rows/imports; added persistent DELETE row and CLI PTY import. First Clippy attempts blocked by sccache incremental policy and missing embedded bundle; disabled wrapper and built locked web dependencies. 2. multitab-refresh: clean textual merge; auth implementation, Vitest tests, browser-check and verify changes retained. Clippy passed. 3. fix-scale-podman: eight conflicts, all overlapping Rust 1.99 empty-value assertions already fixed differently on dev. Kept dev typed-empty-array assertions and existing security regression additions; preserved bounded collector, independent Podman discovery, coalesced invalidations and true resync-gap semantics. 4. cli-mcp-actions: six conflicted files. Kept dev assertion fixes, added the incoming server-tail/follow regression, and used the incoming tested MSRV-compatible atomic compare-exchange helper at both admission sites. Removed superseded deprecation comments/allowances. Retained scale event semantics and existing security tests. 5. embedded-list-registry: resolved 24 conflicted paths, including facade modify/delete conflicts. Removed the engine facade and server LocalInventory; moved the bounded event-batch primitive plus four regressions to crates/agent/src/provider_runtime/event_batch.rs. Kept scale ordinary invalidation vs true gap semantics, while forwarding each compact notice into the new bounded runtime ring. Native actor-less events now invalidate normally instead of fabricating a gap. Retained the new event normalization and adapted the existing secret-redaction regression to the provider envelope. Kept remote SSH directives, ownership, identity-stop deadlines, tunnel controls, confirmed/absent DELETE acknowledgements, CLI tail/follow tests, and dev assertion fixes. Adapted security sweep fixtures to LocalHost + HostRouter. Removed legacy RemoteInventory-only tests with that removed path; registry tests/real audit check cover the replacement. Preserved native collector table, updated provider and remote SSH contract text. Clippy caught duplicate imports and stale API/facade references; fixed them without restoring the old path. Integration fixes beyond the merges: - 51cb880: compact-ring test admits two ordinary notices before injecting actual overflow. - 1939d36: real stream fixtures wait for exact inventory readiness before OPEN or dispatch failure injection; authorization and cleanup deadlines stay unchanged. - ca3d71d: failed/incomplete bounded scans retry after one second on the same native feed, including idle initial and post-resync failure. Healthy feeds do not poll or construct a timer. Seventeen provider-runtime tests and thirteen real stream regressions pass. docs/contracts.md records the policy. - 714fa1e: HTTP readiness helper retains typed ApiError responses, allowing the existing 200/503 readiness polling to run without decoding an error as a container list. - 66b4eaf: serialize real-client scenarios and isolate their temporary credential config paths; four combined CLI/MCP tests pass in one process. Validation on final head: - Required INFRATERNAL_VERIFY_RUN_ID=batch3 scripts/verify fast: PASS. Cargo fmt, Clippy, workspace tests, frontend typechecks, auth Vitest, generated OpenAPI/TypeScript-client drift and terminal checks pass. - scripts/verify integration: PASS on 66b4eaf. - scripts/verify merge: PASS on 66b4eaf. - Full e2e-remote parity: 60/60 PASS, 0 expected failures, cleanup_errors=[]. - SDP audit: 13/13 PASS, cleanup completed. Both embedded and enrolled remote Docker/Podman paths; server-applied tail+follow; successful DELETE confirms native shell is gone and attached stream closes; DOCKER_HOST points to Docker while Podman stays independent; all 305 exact native IDs appear through both APIs and compiled CLIs for each engine. Parity and SDP evidence used ca3d71d production code. Diff ca3d71d..66b4eaf changes only crates/server/tests/resources_http.rs and crates/infraternal/tests/cli_mcp.rs, so the production code is identical. Additional real tests: provider-podman/real 3 PASS (rootful, rootless, DOCKER_HOST isolation); provider-docker/real 1 PASS; provider_real 2 PASS (signed parity/reconnect and 305-container remote-runtime burst); real_sshd 15 PASS; ssh_product 4 PASS; agent_tunnel with Docker+liveness 1 PASS; remote_ssh 1 PASS. Evidence: - Gate logs and additional test logs: /mnt/hdd/infraternal/artifacts/verify/batch3/. - SDP runner and JSON: /mnt/hdd/infraternal/artifacts/verify/batch3/audit-final/. - Parity report: /mnt/hdd/infraternal/artifacts/verify/batch3-parity-recovery/e2e/remote-batch3-parity-recovery/report.json. - Final-head browser screenshots: /mnt/hdd/infraternal/artifacts/verify/batch3-merge-final-head/browser/ (desktop and 390×844). Failed runs are retained in batch3-integration, batch3-integration-final, batch3-integration-recovery, batch3-integration-complete and batch3-remote artifact directories. They exposed startup-readiness races, idle-feed scan recovery, and test-fixture collisions corrected above. An embedded Podman inventory deadline and a persistent SSH replay exit deadline did not recur in targeted or full rechecks; their precise causes were not proven, and no deadlines or expected-failure policy were relaxed. Successful CLI schema validation prints caught alternate-schema assertion panics; its actual test result is 4 passed, 0 failed. Measurements here are dev-VM diagnostics, not a new performance-VM A/B certification. Existing low cookie advisory remains report-only under repository policy. All commits carry the requested trailers. No generated caches, benchmark data, credentials or secrets were committed. Working tree is clean; the temporary target symlink was removed. All five incoming heads are ancestors of HEAD; all ten first-parent integration commits have the requested trailers. No push and no issues closed. Successful per-merge Clippy output tails (command: RUSTC_WRAPPER= CARGO_INCREMENTAL=0 cargo clippy --workspace --all-targets -- -D warnings): fix-sessions-pty: ``` Finished `dev` profile [unoptimized] target(s) in 30.91s ``` multitab-refresh: ``` Finished `dev` profile [unoptimized] target(s) in 0.50s ``` fix-scale-podman: ``` Finished `dev` profile [unoptimized] target(s) in 30.36s ``` cli-mcp-actions: ``` Finished `dev` profile [unoptimized] target(s) in 28.41s ``` embedded-list-registry: ``` Finished `dev` profile [unoptimized] target(s) in 0.90s ``` Required fast gate, output excerpt quoted verbatim: ``` PASS fast: migrations are append-only (0.183s) PASS fast: workspace package dependencies (0.250s) PASS fast: JavaScript dependencies (0.008s) PASS fast: advisory review policy tests (0.148s) PASS fast: supply-chain checks (3.638s) PASS fast: build web app (12.021s) PASS fast: cargo fmt --check (1.330s) PASS fast: cargo clippy (9.893s) PASS fast: cargo test (125.899s) PASS fast: svelte-check (11.027s) PASS fast: UI package svelte-check (6.179s) PASS fast: stream package typecheck (4.224s) PASS fast: Vitest (3.813s) PASS fast: UI package Vitest (12.130s) PASS fast: stream package Vitest (1.283s) PASS fast: OpenAPI and TypeScript client drift (28.547s) PASS fast: terminal TypeScript (3.611s) PASS fast: terminal Vitest (1.734s) ``` Full integration gate, output excerpt quoted verbatim: ``` PASS integration: JavaScript dependencies (0.004s) PASS integration: build web app (11.925s) PASS integration: build release binary (357.443s) PASS integration: real HTTP behavior (0.614s) PASS integration: Docker socket _ping (0.013s) PASS integration: rootless Podman socket _ping (0.012s) PASS integration: engine adapters against Docker and Podman (242.678s) PASS integration: bounded follow:false log snapshots against Docker and rootless Podman (12.838s) PASS integration: TypeScript stream client against Docker and Podman (21.608s) PASS integration: stream authorization and CLOSE regressions against Docker (90.307s) PASS integration: persistent PTY termination preempts blocked send (1.621s) PASS integration: resource HTTP API against Docker and rootless Podman (35.306s) PASS integration: compiled CLI and MCP against real server and engines (130.818s) PASS integration: SSH contract against isolated real sshd (14.658s) PASS integration: SSH product API and stream against isolated real sshd (16.169s) PASS integration: remote mTLS infraternal agent enroll, rotate, list, exec and revoke against Docker (23.978s) PASS integration: remote SSH through the mTLS tunnel against isolated real sshd (4.103s) ``` Merge gate, output excerpt quoted verbatim: ``` PASS merge: build release binary (306.344s) PASS merge: release server HTTP and static behavior (0.467s) PASS merge: Docker socket _ping (0.009s) PASS merge: rootless Podman socket _ping (0.009s) PASS merge: Docker exec PTY smoke (1.129s) PASS merge: rootless Podman inventory and lifecycle smoke (3.289s) PASS merge: real sshd session ownership smoke (0.850s) PASS merge: persistent-session authorization-loss security smoke (1.889s) PASS merge: install Chromium and system dependencies (2.936s) PASS merge: production browser smoke (10.512s) ``` Browser evidence inspected at both sizes: [desktop](/mnt/hdd/infraternal/artifacts/verify/batch3-merge-final-head/browser/multi-tab-supported-1440x900.png), [390×844](/mnt/hdd/infraternal/artifacts/verify/batch3-merge-final-head/browser/multi-tab-supported-390x844.png).
Author
Owner

Browser attempt 17 showed that container detail data had loaded (.mh-title and the runtime facts were present), but the standalone Open terminal action was absent. The generated container name overflowed the header, so ModeHeader correctly folded the page action into the title menu; the accessible tree exposed the title switcher button and the header had no inline action buttons. This is the responsive menu path, not a missing product action. I am updating openTerminalInCurrentPage to invoke either the inline button or the folded Open terminal menu item.

Browser attempt 17 showed that container detail data had loaded (`.mh-title` and the runtime facts were present), but the standalone `Open terminal` action was absent. The generated container name overflowed the header, so `ModeHeader` correctly folded the page action into the title menu; the accessible tree exposed the title switcher button and the header had no inline action buttons. This is the responsive menu path, not a missing product action. I am updating `openTerminalInCurrentPage` to invoke either the inline button or the folded `Open terminal` menu item.
Author
Owner

Browser attempt 18 passed the folded terminal action path and terminal attach/reattach checks, then failed in runTerminalMarker for the split pane. The generated marker included the full long browser run id; the split pane wrapped the marker across rows, and the accessible terminal log exposed NUL-padded cells, so Playwright's contiguous toContainText(marker) timed out even though terminal DATA arrived. I am shortening only the split/pane markers to a unique 10-character run-id suffix so each marker fits the split width; the exact output assertion remains.

Browser attempt 18 passed the folded terminal action path and terminal attach/reattach checks, then failed in `runTerminalMarker` for the split pane. The generated marker included the full long browser run id; the split pane wrapped the marker across rows, and the accessible terminal log exposed NUL-padded cells, so Playwright's contiguous `toContainText(marker)` timed out even though terminal DATA arrived. I am shortening only the split/pane markers to a unique 10-character run-id suffix so each marker fits the split width; the exact output assertion remains.
Author
Owner

Browser attempt #19 reached session pagination, then failed on /terminals: the header still displayed Page after the 5 s toContainText("Terminals") default timeout. The shared header can render before the route component registers its page chrome. expectShellTitle already allows 45 s for the header node because uncached asset delivery took over 20 s on a loaded host; I aligned the title condition with that same evidence-based cold-load envelope. The assertion still waits for the actual route title and no product budget changed.

Browser attempt #19 reached session pagination, then failed on `/terminals`: the header still displayed `Page` after the 5 s `toContainText("Terminals")` default timeout. The shared header can render before the route component registers its page chrome. `expectShellTitle` already allows 45 s for the header node because uncached asset delivery took over 20 s on a loaded host; I aligned the title condition with that same evidence-based cold-load envelope. The assertion still waits for the actual route title and no product budget changed.
Author
Owner

Browser attempt #20 passed the session-pagination route transition (the /terminals title condition cleared) and later failed in checkTerminalWorkspace on the second marker. The expected workspace-second-verify-… string was present in the terminal transcript but split across rows at …-254 / 18; transcript padding cells prevent toContainText from matching across the wrap. I shortened all workspace markers to the same 10-character run-id suffix while retaining distinct prefixes. This keeps exact output assertions and does not change product behavior or timing budgets.

Browser attempt #20 passed the session-pagination route transition (the `/terminals` title condition cleared) and later failed in `checkTerminalWorkspace` on the second marker. The expected `workspace-second-verify-…` string was present in the terminal transcript but split across rows at `…-254` / `18`; transcript padding cells prevent `toContainText` from matching across the wrap. I shortened all workspace markers to the same 10-character run-id suffix while retaining distinct prefixes. This keeps exact output assertions and does not change product behavior or timing budgets.
Author
Owner

Browser attempt #21 passed the route title and all shortened workspace marker assertions, then reached the mobile sidebar group drag. The check first resets and asserts the default three groups (Infrastructure, Access, Admin) but expected the announcement Access group moved, position 1 of 2. The UI correctly announced position 1 of 3. I changed the expected count to use the established groupsBeforeTouch.length, preserving the exact order and announcement checks.

Browser attempt #21 passed the route title and all shortened workspace marker assertions, then reached the mobile sidebar group drag. The check first resets and asserts the default three groups (`Infrastructure`, `Access`, `Admin`) but expected the announcement `Access group moved, position 1 of 2.` The UI correctly announced `position 1 of 3.` I changed the expected count to use the established `groupsBeforeTouch.length`, preserving the exact order and announcement checks.
Author
Owner

Browser attempt #22 passed the mobile group-position announcement, then failed when checking the Access item order. After restoring defaults, Access contains terminals; moving Containers into it correctly produced ["containers", "terminals"], while the fixture expected only ["containers"] and position 1 of 1. I added an explicit default Access item assertion, then derive the expected post-move order and announcement count from that baseline. The check still verifies Containers is inserted first and Terminals remains present.

Browser attempt #22 passed the mobile group-position announcement, then failed when checking the Access item order. After restoring defaults, Access contains `terminals`; moving Containers into it correctly produced `["containers", "terminals"]`, while the fixture expected only `["containers"]` and `position 1 of 1`. I added an explicit default Access item assertion, then derive the expected post-move order and announcement count from that baseline. The check still verifies Containers is inserted first and Terminals remains present.
Author
Owner

Browser attempt #23 reached checkLogControls and failed after ArrowUp: Jump to latest became visible, but the first visible virtual-row index remained 238 for the 5 s assertion requiring it to decrease. The verifier warned load5=11.05 with 8 online CPUs, and a separate build was active in another worktree. This is the existing load-sensitive scroll condition; I am rerunning it unchanged after that work clears before deciding whether the condition or product needs a change.

Browser attempt #23 reached `checkLogControls` and failed after ArrowUp: `Jump to latest` became visible, but the first visible virtual-row index remained `238` for the 5 s assertion requiring it to decrease. The verifier warned `load5=11.05` with 8 online CPUs, and a separate build was active in another worktree. This is the existing load-sensitive scroll condition; I am rerunning it unchanged after that work clears before deciding whether the condition or product needs a change.
Author
Owner

Browser attempt #24 reproduced the same log-control failure: after ArrowUp, Jump to latest was visible, but the first visible row index was 498 against a starting index of 496, failing the toBeLessThan assertion at scripts/browser-check.mjs:2736. The host load rose to 21.72 during this run, and a separate fix-engine-avail workspace test started concurrently. This does not satisfy the requested isolated rerun, so I have not changed the scroll assertion.

Browser attempt #24 reproduced the same log-control failure: after ArrowUp, `Jump to latest` was visible, but the first visible row index was `498` against a starting index of `496`, failing the `toBeLessThan` assertion at `scripts/browser-check.mjs:2736`. The host load rose to 21.72 during this run, and a separate `fix-engine-avail` workspace test started concurrently. This does not satisfy the requested isolated rerun, so I have not changed the scroll assertion.
Author
Owner

Browser attempt #25 failed again at checkLogControls after ArrowUp: the first visible virtual-row index stayed at 470 for 5 s, so it did not satisfy the < 470 assertion at scripts/browser-check.mjs:2736. The gate started with load5=12.13; another e2e-remote run started during the browser step. This is another non-isolated result. No product code or assertion was changed; I will wait for a quiet run to confirm the behavior.

Browser attempt #25 failed again at `checkLogControls` after ArrowUp: the first visible virtual-row index stayed at `470` for 5 s, so it did not satisfy the `< 470` assertion at `scripts/browser-check.mjs:2736`. The gate started with `load5=12.13`; another `e2e-remote` run started during the browser step. This is another non-isolated result. No product code or assertion was changed; I will wait for a quiet run to confirm the behavior.
Author
Owner

The repeated log-control failures returned a real row index, rather than the Number.MAX_SAFE_INTEGER sentinel used when “Jump to latest” is hidden. In all three observed failures the jump button was visible, while the first visible virtual-row index was unchanged or moved forward after ArrowUp. That index is quantized to whole rows and does not prove whether the scroll position moved within a row. I changed the browser assertion to press End, wait for the actual bottom gap and hidden jump control, then press ArrowUp and require both a decreased scrollTop and visible “Jump to latest.” The final jump still has to return the viewport to within 32 px of the end. No product code or product budget changed.

The repeated log-control failures returned a real row index, rather than the `Number.MAX_SAFE_INTEGER` sentinel used when “Jump to latest” is hidden. In all three observed failures the jump button was visible, while the first visible virtual-row index was unchanged or moved forward after ArrowUp. That index is quantized to whole rows and does not prove whether the scroll position moved within a row. I changed the browser assertion to press End, wait for the actual bottom gap and hidden jump control, then press ArrowUp and require both a decreased `scrollTop` and visible “Jump to latest.” The final jump still has to return the viewport to within 32 px of the end. No product code or product budget changed.
Author
Owner

Browser attempt #26 passed the release build and terminal fixture, then failed before the log control check during a container-detail navigation. waitForAppSurface observed document.readyState=complete with zero route surfaces and page error Failed to fetch dynamically imported module: .../entry/app.CbsTahcw.js; eight app chunk requests failed with net::ERR_NETWORK_CHANGED. This is a browser/network loading failure, not a route assertion or product code change. I am checking for concurrent tests/network activity before retrying.

Browser attempt #26 passed the release build and terminal fixture, then failed before the log control check during a container-detail navigation. `waitForAppSurface` observed `document.readyState=complete` with zero route surfaces and page error `Failed to fetch dynamically imported module: .../entry/app.CbsTahcw.js`; eight app chunk requests failed with `net::ERR_NETWORK_CHANGED`. This is a browser/network loading failure, not a route assertion or product code change. I am checking for concurrent tests/network activity before retrying.
Author
Owner

Lifecycle review fixes committed on calternal-port at e9ba32b4669ff4141ab8d8d22e4a99f07ccef8f5 (base 76db215). The root client hook and shared page-lifecycle module register the bfcache reload fence before route pollers initialize; API dispatch rejects work from retired documents; stream recovery checks lifecycle state after auth recovery and connection awaits; and a sign-out epoch change cancels the peer wait before it can refresh. Vitest cases cover the API/poller fence, stream recovery after pagehide, and sign-out cancellation. The focused web run passed 4 files / 38 tests; browser and final fast gates remain pending.

Lifecycle review fixes committed on `calternal-port` at `e9ba32b4669ff4141ab8d8d22e4a99f07ccef8f5` (base `76db215`). The root client hook and shared page-lifecycle module register the bfcache reload fence before route pollers initialize; API dispatch rejects work from retired documents; stream recovery checks lifecycle state after auth recovery and connection awaits; and a sign-out epoch change cancels the peer wait before it can refresh. Vitest cases cover the API/poller fence, stream recovery after `pagehide`, and sign-out cancellation. The focused web run passed 4 files / 38 tests; browser and final `fast` gates remain pending.
Author
Owner

Browser attempt 27 built the release binary and passed the terminal fixture. The main Playwright suite reached checkLogControls and exposed a test-harness bug: scrollTopAtLatest was closed over inside locator.evaluate, whose callback runs in the page and cannot access Node scope (ReferenceError: scrollTopAtLatest is not defined). Fixed the check to pass the captured scroll position as the evaluate argument. git diff --check passes, and scripts/browser-check.mjs still has no networkidle or fixed waitForTimeout calls. Retrying after shared service activity clears.

Browser attempt 27 built the release binary and passed the terminal fixture. The main Playwright suite reached `checkLogControls` and exposed a test-harness bug: `scrollTopAtLatest` was closed over inside `locator.evaluate`, whose callback runs in the page and cannot access Node scope (`ReferenceError: scrollTopAtLatest is not defined`). Fixed the check to pass the captured scroll position as the evaluate argument. `git diff --check` passes, and `scripts/browser-check.mjs` still has no `networkidle` or fixed `waitForTimeout` calls. Retrying after shared service activity clears.
Author
Owner

Browser attempt 28 passed the web build, release binary build (359.734s) and terminal fixture (50.269s). The main production-browser run failed while importing the container detail route: the server returned HTTP 200 with an internal-error page, and seven app chunk requests reported net::ERR_NETWORK_CHANGED. The same failure also occurred in attempt 26; external merge and integration jobs overlapped both runs. No product code was changed for this failure. Retrying once shared network/test activity clears; waitForAppSurface continues to require an actual route or auth surface and does not accept load-only readiness.

Browser attempt 28 passed the web build, release binary build (`359.734s`) and terminal fixture (`50.269s`). The main production-browser run failed while importing the container detail route: the server returned HTTP 200 with an internal-error page, and seven app chunk requests reported `net::ERR_NETWORK_CHANGED`. The same failure also occurred in attempt 26; external merge and integration jobs overlapped both runs. No product code was changed for this failure. Retrying once shared network/test activity clears; `waitForAppSurface` continues to require an actual route or auth surface and does not accept load-only readiness.
Author
Owner

Because attempts 26 and 28 both recorded external test/build overlap and the same app-chunk net::ERR_NETWORK_CHANGED, navigateToAppSurface now retries exactly once only when the first HTML response is 200, the page reports a failed dynamic import, and a request to /_app/immutable/ failed with that exact network error. The retry still waits for #route-content or .auth-screen; a persistent or unrelated failure remains fatal. No fixed sleep or network-idle wait was added. This harness change is pending another browser run.

Because attempts 26 and 28 both recorded external test/build overlap and the same app-chunk `net::ERR_NETWORK_CHANGED`, `navigateToAppSurface` now retries exactly once only when the first HTML response is 200, the page reports a failed dynamic import, and a request to `/_app/immutable/` failed with that exact network error. The retry still waits for `#route-content` or `.auth-screen`; a persistent or unrelated failure remains fatal. No fixed sleep or network-idle wait was added. This harness change is pending another browser run.
Author
Owner

Browser attempt 29 passed the terminal fixture, log controls, sidebar persistence, container actions and route-size checks; the one-shot chunk-network retry recovered twice. It then found that the authenticated shell showed Page on /terminals after 45 s because AppShell.titleForPath had no /terminals entry, while route-specific chrome was delayed. Added the canonical Terminals fallback in packages/web/src/lib/shell/AppShell.svelte; the header will stay correct on first render and remain consistent when page chrome registers. The external run also had active remote tunnel/sshd sessions; the production browser retry is still required.

Browser attempt 29 passed the terminal fixture, log controls, sidebar persistence, container actions and route-size checks; the one-shot chunk-network retry recovered twice. It then found that the authenticated shell showed `Page` on `/terminals` after 45 s because `AppShell.titleForPath` had no `/terminals` entry, while route-specific chrome was delayed. Added the canonical `Terminals` fallback in `packages/web/src/lib/shell/AppShell.svelte`; the header will stay correct on first render and remain consistent when page chrome registers. The external run also had active remote tunnel/sshd sessions; the production browser retry is still required.
Author
Owner

Browser attempt 30 passed the web build, release binary (498.636s), terminal fixture (142.729s), all auth multi-tab cases, sidebar persistence, container actions and the /terminals route title fallback. It reached checkLogControls and failed the 5-second ArrowUp condition requiring the log viewport's scrollTop to move below its end position. At failure, host load was 45.82 with two external scripts/verify fast runs and workspace cargo work active. No product change was made; rerun this check once the host is quiet before deciding whether the assertion or behavior is wrong.

Browser attempt 30 passed the web build, release binary (`498.636s`), terminal fixture (`142.729s`), all auth multi-tab cases, sidebar persistence, container actions and the `/terminals` route title fallback. It reached `checkLogControls` and failed the 5-second ArrowUp condition requiring the log viewport's `scrollTop` to move below its end position. At failure, host load was 45.82 with two external `scripts/verify fast` runs and workspace cargo work active. No product change was made; rerun this check once the host is quiet before deciding whether the assertion or behavior is wrong.
Author
Owner

Browser attempt #30 failed in checkLogControls after ArrowUp. The fixture emits stdout and stderr every 100ms (scripts/browser-check.mjs:4354), while the assertion captured scrollTopAtLatest before the key press. A newly followed row can advance the viewport beyond that stale sample between Playwright actions, so actual upward movement still compares greater than or equal to the old value. I changed the browser assertion to capture scrollTop during the ArrowUp keydown, require the Jump button to appear, and then require scrollTop to decrease. The 5-second assertion budget is unchanged. The next release browser gate is waiting for shared-host isolation: at 03:55 UTC the VM load was 30.61, with a 16-worker stress-ng run and other cargo jobs active. I did not change or stop those external processes.

Browser attempt #30 failed in `checkLogControls` after ArrowUp. The fixture emits stdout and stderr every 100ms (`scripts/browser-check.mjs:4354`), while the assertion captured `scrollTopAtLatest` before the key press. A newly followed row can advance the viewport beyond that stale sample between Playwright actions, so actual upward movement still compares greater than or equal to the old value. I changed the browser assertion to capture scrollTop during the ArrowUp keydown, require the Jump button to appear, and then require scrollTop to decrease. The 5-second assertion budget is unchanged. The next release browser gate is waiting for shared-host isolation: at 03:55 UTC the VM load was 30.61, with a 16-worker stress-ng run and other cargo jobs active. I did not change or stop those external processes.
Author
Owner

Shared-host isolation is still unavailable. At 04:14 UTC, load was 32.35 / 24.69 / 23.30 (1/5/15 min); external verify fast, agent-tunnel/stream regression tests, and a workspace test were active. No rs-port build or gate is running. I am leaving those processes untouched and will rerun browser only after the recorded load5 < 8/no competing heavy-gate condition.

Shared-host isolation is still unavailable. At 04:14 UTC, load was 32.35 / 24.69 / 23.30 (1/5/15 min); external verify fast, agent-tunnel/stream regression tests, and a workspace test were active. No rs-port build or gate is running. I am leaving those processes untouched and will rerun browser only after the recorded load5 < 8/no competing heavy-gate condition.
Author
Owner

Follow-up on host isolation: a new external 16-worker stress run appeared after the prior cargo jobs cleared. stress-ng --cpu 16 --timeout 1800s --metrics-brief started about 04:07 UTC (elapsed 12:17 at 04:20 UTC), keeping CPU load high; I have not touched it. Based on its timeout, it should end around 04:37 UTC, then I will wait for load5 < 8 and recheck for competing gates before running browser.

Follow-up on host isolation: a new external 16-worker stress run appeared after the prior cargo jobs cleared. `stress-ng --cpu 16 --timeout 1800s --metrics-brief` started about 04:07 UTC (elapsed 12:17 at 04:20 UTC), keeping CPU load high; I have not touched it. Based on its timeout, it should end around 04:37 UTC, then I will wait for load5 < 8 and recheck for competing gates before running browser.
Author
Owner

The previous stress window and external fast gate cleared, but a second stress run started immediately afterward. At 04:40 UTC, stress-ng --cpu 16 --timeout 1800s --metrics-brief had been active for 00:27, alongside a server regression test; load was 13.49 / 19.71 / 22.72 (1/5/15 min). I am leaving both alone and will wait for the host to settle again before browser/fast.

The previous stress window and external fast gate cleared, but a second stress run started immediately afterward. At 04:40 UTC, `stress-ng --cpu 16 --timeout 1800s --metrics-brief` had been active for 00:27, alongside a server regression test; load was 13.49 / 19.71 / 22.72 (1/5/15 min). I am leaving both alone and will wait for the host to settle again before browser/fast.
Author
Owner

After the previous 16/8-worker stress windows ended, a third wave started within minutes. At 04:58 UTC, new stress-ng --cpu 16 --timeout 1800s and --cpu 8 --timeout 1800s processes were active, with cargo stream tests and a debug build; load was 22.34 / 27.75 / 28.56 (1/5/15 min). This restarts the isolation wait. No rs-port gates or external processes were started/stopped by me.

After the previous 16/8-worker stress windows ended, a third wave started within minutes. At 04:58 UTC, new `stress-ng --cpu 16 --timeout 1800s` and `--cpu 8 --timeout 1800s` processes were active, with cargo stream tests and a debug build; load was 22.34 / 27.75 / 28.56 (1/5/15 min). This restarts the isolation wait. No rs-port gates or external processes were started/stopped by me.
Author
Owner

After the stress processes disappeared, another worktree started scripts/verify merge and cargo metadata, with its e2e server still active. At 05:00 UTC the high-CPU list showed cargo metadata at 104% CPU; load remained 10.67 / 23.21 / 26.91. The rs-port browser/fast gates remain idle pending isolation.

After the stress processes disappeared, another worktree started `scripts/verify merge` and cargo metadata, with its e2e server still active. At 05:00 UTC the high-CPU list showed cargo metadata at 104% CPU; load remained 10.67 / 23.21 / 26.91. The rs-port browser/fast gates remain idle pending isolation.
Author
Owner

Starting the release browser gate from branch calternal-port at b66eb30. The ArrowUp assertion is anchored at keydown; it still requires the Jump button and actual upward viewport movement within the existing 5-second budget. Preflight at 05:42 UTC: /mnt/hdd has 205 GB free, load5 is 3.41, and no competing merge/browser/cargo work is active.

Starting the release browser gate from branch `calternal-port` at `b66eb30`. The ArrowUp assertion is anchored at keydown; it still requires the Jump button and actual upward viewport movement within the existing 5-second budget. Preflight at 05:42 UTC: `/mnt/hdd` has 205 GB free, load5 is 3.41, and no competing merge/browser/cargo work is active.
Author
Owner

Browser attempt #31 ran at load5 3.12 and failed checkLogControls paused-count stability: expected 278, observed 280 after 2s. Source confirms the race: LogFrameBatcher.consume() appends decoded records immediately and publishes logVersion on the next animation frame; the test sampled data-log-total before that already-consumed batch flushed. Added a wait for the next real animation frame before taking the paused-count snapshot. No fixed sleep or timeout/budget increase. Rerunning the full release browser gate after committing.

Browser attempt #31 ran at load5 3.12 and failed `checkLogControls` paused-count stability: expected 278, observed 280 after 2s. Source confirms the race: `LogFrameBatcher.consume()` appends decoded records immediately and publishes `logVersion` on the next animation frame; the test sampled `data-log-total` before that already-consumed batch flushed. Added a wait for the next real animation frame before taking the paused-count snapshot. No fixed sleep or timeout/budget increase. Rerunning the full release browser gate after committing.
Author
Owner

Restarting the full release browser gate on calternal-port at f2a15e1. Preflight at 05:52 UTC: /mnt/hdd has 205 GB free, load5 is 2.79, and no external merge/browser/cargo work is active. This attempt includes the animation-frame barrier for the already-consumed log batch before the paused-count snapshot.

Restarting the full release browser gate on `calternal-port` at `f2a15e1`. Preflight at 05:52 UTC: `/mnt/hdd` has 205 GB free, load5 is 2.79, and no external merge/browser/cargo work is active. This attempt includes the animation-frame barrier for the already-consumed log batch before the paused-count snapshot.
Author
Owner

Starting ship-ui on branch calternal-port at base head f2a15e1f93d59a10ad5b77bd85f02a8f63d2fff3. I will merge 8632a04 and dev (6b17a8c), resolve conflicts, run the requested clippy/Svelte/Vitest/fast gates and production browser smoke, and check the three majors from review-port-reload.

Starting ship-ui on branch `calternal-port` at base head `f2a15e1f93d59a10ad5b77bd85f02a8f63d2fff3`. I will merge `8632a04` and `dev` (`6b17a8c`), resolve conflicts, run the requested clippy/Svelte/Vitest/fast gates and production browser smoke, and check the three majors from review-port-reload.
Author
Owner

The 8632a04 merge conflicted in scripts/browser-check.mjs because its route navigations predate the current app-surface readiness and lifecycle checks. I kept the calternal-port navigation/readiness coverage and reconciled the container filter assertions with the merged DataTable's accessible host/status/engine chip groups, including selection/reset checks. git diff --check passed; no conflict markers remain in the merged container, host, DataTable, or browser-check files.

The `8632a04` merge conflicted in `scripts/browser-check.mjs` because its route navigations predate the current app-surface readiness and lifecycle checks. I kept the `calternal-port` navigation/readiness coverage and reconciled the container filter assertions with the merged DataTable's accessible host/status/engine chip groups, including selection/reset checks. `git diff --check` passed; no conflict markers remain in the merged container, host, DataTable, or browser-check files.
Author
Owner

Finding from the reload/auth majors: signOut() waited for beforeSignOutConsumers before marking the local sign-out generation or waking session waiters. A stalled preference flush therefore let a newer-generation peer wait reach its timeout and fall through toward refresh; if that continuation started after clear(), it could capture the new epoch. I moved the signed-out fence, broadcast, and waiter notification before the flush while keeping the captured access credential available to the flush. Added a regression test that holds the preference flush and asserts no second refresh is dispatched.

Finding from the reload/auth majors: `signOut()` waited for `beforeSignOutConsumers` before marking the local sign-out generation or waking session waiters. A stalled preference flush therefore let a newer-generation peer wait reach its timeout and fall through toward refresh; if that continuation started after `clear()`, it could capture the new epoch. I moved the signed-out fence, broadcast, and waiter notification before the flush while keeping the captured access credential available to the flush. Added a regression test that holds the preference flush and asserts no second refresh is dispatched.
Author
Owner

Merge-resolution decision on calternal-port: dev's newer typed stream/admission/runtime implementation is retained. I carried forward this branch's WebSocket Ping/Pong deadline and prompt client-close teardown, plus a server-side close log used by the production browser lifecycle check. The stream regression tests cover missed Pong closure and client-close teardown. This keeps dev's current architecture while preserving lifecycle behavior asserted by this UI branch.

Merge-resolution decision on calternal-port: dev's newer typed stream/admission/runtime implementation is retained. I carried forward this branch's WebSocket Ping/Pong deadline and prompt client-close teardown, plus a server-side close log used by the production browser lifecycle check. The stream regression tests cover missed Pong closure and client-close teardown. This keeps dev's current architecture while preserving lifecycle behavior asserted by this UI branch.
Author
Owner

Gate findings and fixes on calternal-port:

  • svelte-check found initialMobileDrawerFocus() could return undefined through optional chaining despite declaring HTMLElement | null; it now returns null when the mobile panel is absent. Recheck: 0 errors, 0 warnings.
  • Vitest found a stale-session adoption path could issue duplicate account probes because both the pending refresh and channel callback loaded the profile. The callback now leaves the probe to the pending refresh, and the regression asserts one initial refresh plus exactly two account reads. The previous test also incorrectly counted the initial refresh as an extra rotation; it now checks for exactly one. Full web Vitest: 13 files and 75 tests passed.
Gate findings and fixes on calternal-port: - svelte-check found `initialMobileDrawerFocus()` could return `undefined` through optional chaining despite declaring `HTMLElement | null`; it now returns `null` when the mobile panel is absent. Recheck: 0 errors, 0 warnings. - Vitest found a stale-session adoption path could issue duplicate account probes because both the pending refresh and channel callback loaded the profile. The callback now leaves the probe to the pending refresh, and the regression asserts one initial refresh plus exactly two account reads. The previous test also incorrectly counted the initial refresh as an extra rotation; it now checks for exactly one. Full web Vitest: 13 files and 75 tests passed.
Author
Owner

verify fast initially failed in scripts/check-supply-chain: it required shadcn-svelte and a packages/ui/src/lib/components/ui tree, while DECISIONS.md §26 and docs/UI.md establish that shadcn was removed and the checked-in UI is ported from calternal. The checker now inventories production dependencies from the current workspace manifests, records files with calternal provenance headers under the repo AGPL license, and no longer attributes nonexistent shadcn source. The generated third-party notice will be refreshed by the next fast gate.

`verify fast` initially failed in `scripts/check-supply-chain`: it required `shadcn-svelte` and a `packages/ui/src/lib/components/ui` tree, while DECISIONS.md §26 and docs/UI.md establish that shadcn was removed and the checked-in UI is ported from calternal. The checker now inventories production dependencies from the current workspace manifests, records files with calternal provenance headers under the repo AGPL license, and no longer attributes nonexistent shadcn source. The generated third-party notice will be refreshed by the next fast gate.
Author
Owner

The first release-browser run failed checkSharedCookieTabs with supported mode issued 2 refresh requests for two simultaneous tabs. The test's route handler blocked only after route.fetch() had received a response, while the test opened that gate as soon as it observed a queued Web Lock. Under load, the lock observation can precede the buffered response. I tightened the synchronization to require both the first response to be held and the peer lock request to be pending before releasing it; the one-refresh assertion remains unchanged. I am rerunning the production browser check to verify this wait fix.

The first release-browser run failed `checkSharedCookieTabs` with `supported mode issued 2 refresh requests for two simultaneous tabs`. The test's route handler blocked only after `route.fetch()` had received a response, while the test opened that gate as soon as it observed a queued Web Lock. Under load, the lock observation can precede the buffered response. I tightened the synchronization to require both the first response to be held and the peer lock request to be pending before releasing it; the one-refresh assertion remains unchanged. I am rerunning the production browser check to verify this wait fix.
Author
Owner

After the held-response wait fix, the production smoke passed simultaneous shared-cookie refresh with one request, pending-refresh sign-out, fallback modes, and sidebar persistence. It then failed in revealContainerSearch: the merged DataTable exposes role=searchbox with accessible name Filter Containers; the old helper searched for a textbox named Search or a Filters button that this UI no longer has. I updated the helper to wait for and use the current accessible search control.

After the held-response wait fix, the production smoke passed simultaneous shared-cookie refresh with one request, pending-refresh sign-out, fallback modes, and sidebar persistence. It then failed in `revealContainerSearch`: the merged DataTable exposes `role=searchbox` with accessible name `Filter Containers`; the old helper searched for a textbox named `Search` or a `Filters` button that this UI no longer has. I updated the helper to wait for and use the current accessible search control.
Author
Owner

The next production-browser attempt reached the legacy scroll helper after passing the multi-tab, fallback, and sidebar flows. The helper still queried .infrastructure-list .resource-rows; both hosts and containers now use the shared DataTable with .table-viewport, virtual row counts, and filter-chip groups. I aligned the geometry check, mobile/desktop filter interactions, row-cell expectations, and host route selector with the DataTable DOM and accessible controls. The next smoke will validate these assertions.

The next production-browser attempt reached the legacy scroll helper after passing the multi-tab, fallback, and sidebar flows. The helper still queried `.infrastructure-list .resource-rows`; both hosts and containers now use the shared `DataTable` with `.table-viewport`, virtual row counts, and filter-chip groups. I aligned the geometry check, mobile/desktop filter interactions, row-cell expectations, and host route selector with the DataTable DOM and accessible controls. The next smoke will validate these assertions.
Author
Owner

Finished ship-ui #46.

Branch calternal-port, base f2a15e1, final HEAD c7fcea78b30aaed12dc7a3b13e870ce66d9cf40c (clean). No push.

Merged 8632a04 (conflict in scripts/browser-check.mjs) and dev (6b17a8c; conflicts in DECISIONS.md, crates/server/src/stream.rs, crates/server/tests/stream_regressions.rs, docs/UI.md, docs/contracts.md, packages/web/src/lib/auth.svelte.ts, packages/web/src/lib/auth.test.ts, scripts/browser-check.mjs, scripts/verify). Kept dev's scripts/verify target-dir handling; combined the settled calternal UI decision with dev's SSH decision; retained current UI spec; combined the session-generation contract; preserved the WebSocket ping deadline and prompt close teardown alongside dev's typed stream/admission work. Resolved the browser conflict for the accessible DataTable controls. Follow-up fixes: sidebar focus fallback, avoid duplicate account probes during session adoption, replace stale shadcn supply-chain assumptions with calternal provenance, and align browser selectors/waits to DataTable.

Production browser smoke used the release binary with RUSTC_WRAPPER=sccache; invocation matched browser_check_smoke in scripts/verify (direct bun scripts/browser-check.mjs, with the same smoke environment). Smoke output:

PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request)
PASS multi-tab sign-out: pending refresh response cannot restore tab B
PASS multi-tab locks-only: single-tab notice and real stale GET 401/200 recovery after external cookie rotation
PASS multi-tab neither: single-tab notice and real stale GET 401/200 recovery after external cookie rotation
SIDEBAR_PERSISTENCE drag/reload/second-context passed
SIDEBAR_CONTAINERS repetition=1/1 GET /api/v1/containers status=200

Fast gate output (INFRATERMINAL_VERIFY_RUN_ID=ship-ui scripts/verify fast, with sccache):

PASS fast: migrations are append-only (0.116s)
PASS fast: workspace package dependencies (0.206s)
PASS fast: gate target-directory and launch diagnostics tests (0.252s)
PASS fast: JavaScript dependencies (0.004s)
PASS fast: advisory review policy tests (0.110s)
PASS fast: supply-chain checks (3.350s)
PASS fast: build web app (5.941s)
PASS fast: cargo fmt --check (1.108s)
PASS fast: cargo clippy (9.335s)
PASS fast: cargo test (185.034s)
PASS fast: svelte-check (7.991s)
PASS fast: UI package svelte-check (3.597s)
PASS fast: stream package typecheck (3.526s)
PASS fast: Vitest (2.876s)
PASS fast: UI package Vitest (2.887s)
PASS fast: stream package Vitest (0.783s)
PASS fast: OpenAPI and TypeScript client drift (32.408s)
PASS fast: terminal TypeScript (1.879s)
PASS fast: terminal Vitest (1.127s)

verify-summary.txt: Total: 262.530s. Direct workspace clippy (--workspace --all-targets -- -D warnings), web svelte-check, and Vitest also passed. Vitest reported Test Files 13 passed (13) and Tests 75 passed (75).

The three review majors are fixed in the final tree:

  1. Restored/frozen documents are fenced at lifecycle and API boundaries: packages/web/src/lib/page-lifecycle.ts:9, packages/web/src/lib/api.ts:24.
  2. Stream recovery rechecks page eligibility after auth refresh before reconnecting: packages/web/src/lib/stream-attachment.svelte.ts:178 and :183.
  3. Local sign-out advances the epoch, broadcasts sign-out and wakes peer waiters before awaiting preference flush; regression coverage: packages/web/src/lib/auth.svelte.ts:290, packages/web/src/lib/auth.test.ts:268.

Remaining finding: Bun audit reports one low, report-only advisory for transitive cookie@0.6.0 (GHSA-pxg6-pf52-xh8x). The required fast gate and production smoke passed. Per instruction, verify merge was not run; the owner Safari/iOS checklist remains with the owner.

Finished ship-ui #46. Branch `calternal-port`, base `f2a15e1`, final HEAD `c7fcea78b30aaed12dc7a3b13e870ce66d9cf40c` (clean). No push. Merged `8632a04` (conflict in `scripts/browser-check.mjs`) and `dev` (`6b17a8c`; conflicts in `DECISIONS.md`, `crates/server/src/stream.rs`, `crates/server/tests/stream_regressions.rs`, `docs/UI.md`, `docs/contracts.md`, `packages/web/src/lib/auth.svelte.ts`, `packages/web/src/lib/auth.test.ts`, `scripts/browser-check.mjs`, `scripts/verify`). Kept dev's `scripts/verify` target-dir handling; combined the settled calternal UI decision with dev's SSH decision; retained current UI spec; combined the session-generation contract; preserved the WebSocket ping deadline and prompt close teardown alongside dev's typed stream/admission work. Resolved the browser conflict for the accessible DataTable controls. Follow-up fixes: sidebar focus fallback, avoid duplicate account probes during session adoption, replace stale shadcn supply-chain assumptions with calternal provenance, and align browser selectors/waits to DataTable. Production browser smoke used the release binary with `RUSTC_WRAPPER=sccache`; invocation matched `browser_check_smoke` in `scripts/verify` (direct `bun scripts/browser-check.mjs`, with the same smoke environment). Smoke output: ```text PASS multi-tab supported: simultaneous tabs (1 refresh HTTP request) PASS multi-tab sign-out: pending refresh response cannot restore tab B PASS multi-tab locks-only: single-tab notice and real stale GET 401/200 recovery after external cookie rotation PASS multi-tab neither: single-tab notice and real stale GET 401/200 recovery after external cookie rotation SIDEBAR_PERSISTENCE drag/reload/second-context passed SIDEBAR_CONTAINERS repetition=1/1 GET /api/v1/containers status=200 ``` Fast gate output (`INFRATERMINAL_VERIFY_RUN_ID=ship-ui scripts/verify fast`, with sccache): ```text PASS fast: migrations are append-only (0.116s) PASS fast: workspace package dependencies (0.206s) PASS fast: gate target-directory and launch diagnostics tests (0.252s) PASS fast: JavaScript dependencies (0.004s) PASS fast: advisory review policy tests (0.110s) PASS fast: supply-chain checks (3.350s) PASS fast: build web app (5.941s) PASS fast: cargo fmt --check (1.108s) PASS fast: cargo clippy (9.335s) PASS fast: cargo test (185.034s) PASS fast: svelte-check (7.991s) PASS fast: UI package svelte-check (3.597s) PASS fast: stream package typecheck (3.526s) PASS fast: Vitest (2.876s) PASS fast: UI package Vitest (2.887s) PASS fast: stream package Vitest (0.783s) PASS fast: OpenAPI and TypeScript client drift (32.408s) PASS fast: terminal TypeScript (1.879s) PASS fast: terminal Vitest (1.127s) ``` `verify-summary.txt`: `Total: 262.530s`. Direct workspace clippy (`--workspace --all-targets -- -D warnings`), web `svelte-check`, and Vitest also passed. Vitest reported `Test Files 13 passed (13)` and `Tests 75 passed (75)`. The three review majors are fixed in the final tree: 1. Restored/frozen documents are fenced at lifecycle and API boundaries: `packages/web/src/lib/page-lifecycle.ts:9`, `packages/web/src/lib/api.ts:24`. 2. Stream recovery rechecks page eligibility after auth refresh before reconnecting: `packages/web/src/lib/stream-attachment.svelte.ts:178` and `:183`. 3. Local sign-out advances the epoch, broadcasts sign-out and wakes peer waiters before awaiting preference flush; regression coverage: `packages/web/src/lib/auth.svelte.ts:290`, `packages/web/src/lib/auth.test.ts:268`. Remaining finding: Bun audit reports one low, report-only advisory for transitive `cookie@0.6.0` (`GHSA-pxg6-pf52-xh8x`). The required fast gate and production smoke passed. Per instruction, `verify merge` was not run; the owner Safari/iOS checklist remains with the owner.
Author
Owner

Browser screenshot artifacts from the production smoke are at /mnt/hdd/infraternal/artifacts/verify/ship-ui/browser/: light/dark setup and sign-in screenshots at 1440×900 and 390×844, plus locks-only and no-fallback multi-tab screenshots at both sizes. The smoke exercised the signed-in Containers DataTable and sidebar persistence.

Browser screenshot artifacts from the production smoke are at `/mnt/hdd/infraternal/artifacts/verify/ship-ui/browser/`: light/dark setup and sign-in screenshots at 1440×900 and 390×844, plus locks-only and no-fallback multi-tab screenshots at both sizes. The smoke exercised the signed-in Containers DataTable and sidebar persistence.
Author
Owner

Started read-only review #46 in /mnt/hdd/infraternal/wt-lp/review-ship-ui, detached calternal-port HEAD 1dd62b854f. Base dev ea776ea. Scope: auth lifecycle fixes and server stream liveness/peer-close cleanup; server stream unit tests, stream_regressions and web Vitest. Using inherited sccache preset/debug builds; no verify merge, commits or pushes.

Started read-only review #46 in /mnt/hdd/infraternal/wt-lp/review-ship-ui, detached calternal-port HEAD 1dd62b854fbdedadd9611c07b5bf19cd067cf9ae. Base dev ea776ea. Scope: auth lifecycle fixes and server stream liveness/peer-close cleanup; server stream unit tests, stream_regressions and web Vitest. Using inherited sccache preset/debug builds; no verify merge, commits or pushes.
Author
Owner

Verdict: merge (correctness/security review of the requested scope; not the required merge gate).

Reviewed detached HEAD 1dd62b854fbdedadd9611c07b5bf19cd067cf9ae against dev ea776ea, including git diff ea776ea...1dd62b8 for the auth/stream paths and git diff ea776ea 1dd62b8 -- crates/server. No blocker or major found. No source edits, commits or pushes.

Severity Location Before After / recommendation Evidence and impact
Minor crates/server/src/stream.rs:1159; crates/server/tests/stream_regressions.rs:249 Receiving peer Close now drops the source and aborts the writer immediately. Preserve a short bounded close-reply flush before dropping the transport, independently of native/durable cleanup; require a Close reply in the regression. Installed tokio-tungstenite/tungstenite 0.29.0 returns the incoming Close with its automatic reply still queued (protocol/mod.rs:245, :475, :737). This branch never polls the source again or explicitly flushes the sink, and aborts the writer that could flush it. Thus graceful close is not guaranteed; the regression accepts an error or EOF as success. This is a protocol/interoperability limitation, not a cleanup or authorization bypass. The old teardown also lacked an explicit reply flush; the immediate abort removes any opportunity for queued writer work to flush it.

The minor is supported by the installed dependency source and RFC 6455 §5.5.1, which requires a reply to an incoming Close. Axum's Message documentation distinguishes an unclean drop from graceful close. It does not block this narrowly requested review.

Previous three majors:

  • Fixed — restored/suspended document dispatch. page-lifecycle.ts:12 synchronously latches suspension on pagehide, before restored visibility can start polling. Persisted pageshow keeps the latch set while requesting reload. api.ts:24 checks it before fetch, after fetch, after recovery and after reading JSON. The visible poller shares that guard. The original pre-pageshow request ordering and work after reload is requested are both fenced.
  • Fixed — recovery completing after pagehide. stream-attachment.svelte.ts:178 and subsequent continuation checks cover refresh and connection awaits; ensureConnected/getClient also guard entry. Pagehide permanently closes the owned StreamClient, whose token/ticket/body continuations check permanent closure. No replacement ticket/socket is dispatched by the retained suspended-document recovery path.
  • Fixed — sign-out during peer wait. auth.svelte.ts:198 checks the epoch captured before the lock/wait; a missing peer returns false instead of falling through into a fresh-epoch refresh. :290 sets signedOut and increments the epoch before preference flushing and wakes waiters. In-flight refresh responses and account responses check their captured epoch. Peer announcements cannot re-enter a signed-out document. Session clear retires the stream, clears registrations/retry timers and ignores old transport/channel callbacks.

Server review:

  • Peer Close still falls through to teardown_connection (stream.rs:1205): stop/join watcher, collect attachment IDs, shutdown native pairs, join the aborted writer, then bounded durable detaches. storage/mod.rs:2303 commits detach state and actor-attributed stream.session.detach audit in the same transaction, keyed by attachment ID. Existing timeout/rollback behavior remains; aborting the writer does not cancel those operations.
  • The revocation watcher and priority writer are unchanged by this diff. Typed forbidden CLOSEs are constructed after their durable audit, use the independent revocation queue and retain the C+850 ms/watchdog path. Immediate writer abort is only selected after an actual inbound peer Close; authorization withdrawal alone does not select it.
  • Only the exact outstanding eight-byte control-Ping payload clears pending state; wrong/unsolicited Pongs cannot satisfy it. This matches RFC 6455 §5.5.3. One outstanding heartbeat bounds state. Nonce allocation occurs on the heartbeat timer, not DATA frames; no new DATA-frame lookup, allocation, copying or lock is introduced.
  • Protocol PING/PONG handling and the 45 s receive-idle check remain. Control Pongs are received messages and update last_received, so they can reset receive-idle and suppress an otherwise-idle protocol Ping; protocol PINGs received from the client still get binary PONGs. A completely silent peer now closes earlier (15 s control Ping + 10 s deadline), as specified in contracts §3.10. The timer starts when Ping is queued, not when the socket flushes; the 10 s limit is therefore a queued-heartbeat bound under backpressure, not a measured wire RTT. Ping intervals are scheduled 15 s after matching Pong receipt.

Scope/skills: loaded emil-design-eng and all seven requested better-* skills. Applied evidence over taste, change-scoped/read-only review, explicit coverage limits, and recovery-copy consistency. Visual layout, typography, color, motion and rendered accessibility were not reviewed by this correctness/security job. No browser screenshots, Safari/iOS checks or perf-VM measurements were taken; no claims of visual or performance certification. Read CLAUDE.md and the requested decision/design/plan/UI/contracts context. Graph absent initially; rebuild initiated into this job's external artifact directory, with raw reads filling its unavailable coverage.

Verification results follow below.

Verdict: **merge** (correctness/security review of the requested scope; not the required merge gate). Reviewed detached HEAD `1dd62b854fbdedadd9611c07b5bf19cd067cf9ae` against dev `ea776ea`, including `git diff ea776ea...1dd62b8` for the auth/stream paths and `git diff ea776ea 1dd62b8 -- crates/server`. No blocker or major found. No source edits, commits or pushes. | Severity | Location | Before | After / recommendation | Evidence and impact | | --- | --- | --- | --- | --- | | Minor | `crates/server/src/stream.rs:1159`; `crates/server/tests/stream_regressions.rs:249` | Receiving peer Close now drops the source and aborts the writer immediately. | Preserve a short bounded close-reply flush before dropping the transport, independently of native/durable cleanup; require a Close reply in the regression. | Installed tokio-tungstenite/tungstenite 0.29.0 returns the incoming Close with its automatic reply still queued (`protocol/mod.rs:245`, `:475`, `:737`). This branch never polls the source again or explicitly flushes the sink, and aborts the writer that could flush it. Thus graceful close is not guaranteed; the regression accepts an error or EOF as success. This is a protocol/interoperability limitation, not a cleanup or authorization bypass. The old teardown also lacked an explicit reply flush; the immediate abort removes any opportunity for queued writer work to flush it. | The minor is supported by the installed dependency source and [RFC 6455 §5.5.1](https://www.rfc-editor.org/rfc/rfc6455.html#section-5.5.1), which requires a reply to an incoming Close. [Axum's Message documentation](https://docs.rs/axum/0.8.9/axum/extract/ws/enum.Message.html#variant.Close) distinguishes an unclean drop from graceful close. It does not block this narrowly requested review. Previous three majors: - **Fixed — restored/suspended document dispatch.** `page-lifecycle.ts:12` synchronously latches suspension on pagehide, before restored visibility can start polling. Persisted pageshow keeps the latch set while requesting reload. `api.ts:24` checks it before fetch, after fetch, after recovery and after reading JSON. The visible poller shares that guard. The original pre-pageshow request ordering and work after reload is requested are both fenced. - **Fixed — recovery completing after pagehide.** `stream-attachment.svelte.ts:178` and subsequent continuation checks cover refresh and connection awaits; ensureConnected/getClient also guard entry. Pagehide permanently closes the owned StreamClient, whose token/ticket/body continuations check permanent closure. No replacement ticket/socket is dispatched by the retained suspended-document recovery path. - **Fixed — sign-out during peer wait.** `auth.svelte.ts:198` checks the epoch captured before the lock/wait; a missing peer returns false instead of falling through into a fresh-epoch refresh. `:290` sets signedOut and increments the epoch before preference flushing and wakes waiters. In-flight refresh responses and account responses check their captured epoch. Peer announcements cannot re-enter a signed-out document. Session clear retires the stream, clears registrations/retry timers and ignores old transport/channel callbacks. Server review: - Peer Close still falls through to `teardown_connection` (`stream.rs:1205`): stop/join watcher, collect attachment IDs, shutdown native pairs, join the aborted writer, then bounded durable detaches. `storage/mod.rs:2303` commits detach state and actor-attributed `stream.session.detach` audit in the same transaction, keyed by attachment ID. Existing timeout/rollback behavior remains; aborting the writer does not cancel those operations. - The revocation watcher and priority writer are unchanged by this diff. Typed forbidden CLOSEs are constructed after their durable audit, use the independent revocation queue and retain the C+850 ms/watchdog path. Immediate writer abort is only selected after an actual inbound peer Close; authorization withdrawal alone does not select it. - Only the exact outstanding eight-byte control-Ping payload clears pending state; wrong/unsolicited Pongs cannot satisfy it. This matches [RFC 6455 §5.5.3](https://www.rfc-editor.org/rfc/rfc6455.html#section-5.5.3). One outstanding heartbeat bounds state. Nonce allocation occurs on the heartbeat timer, not DATA frames; no new DATA-frame lookup, allocation, copying or lock is introduced. - Protocol PING/PONG handling and the 45 s receive-idle check remain. Control Pongs are received messages and update last_received, so they can reset receive-idle and suppress an otherwise-idle protocol Ping; protocol PINGs received from the client still get binary PONGs. A completely silent peer now closes earlier (15 s control Ping + 10 s deadline), as specified in contracts §3.10. The timer starts when Ping is queued, not when the socket flushes; the 10 s limit is therefore a queued-heartbeat bound under backpressure, not a measured wire RTT. Ping intervals are scheduled 15 s after matching Pong receipt. Scope/skills: loaded emil-design-eng and all seven requested better-* skills. Applied evidence over taste, change-scoped/read-only review, explicit coverage limits, and recovery-copy consistency. Visual layout, typography, color, motion and rendered accessibility were not reviewed by this correctness/security job. No browser screenshots, Safari/iOS checks or perf-VM measurements were taken; no claims of visual or performance certification. Read CLAUDE.md and the requested decision/design/plan/UI/contracts context. Graph absent initially; rebuild initiated into this job's external artifact directory, with raw reads filling its unavailable coverage. Verification results follow below.
Author
Owner

Verdict: merge (correctness/security review of the requested scope; not the required merge gate).

Reviewed detached HEAD 1dd62b854fbdedadd9611c07b5bf19cd067cf9ae against dev ea776ea, including git diff ea776ea...1dd62b8 for the auth/stream paths and git diff ea776ea 1dd62b8 -- crates/server. No blocker or major found. No source edits, commits or pushes.

Severity Location Before After / recommendation Evidence and impact
Minor crates/server/src/stream.rs:1159; crates/server/tests/stream_regressions.rs:249 Receiving peer Close now drops the source and aborts the writer immediately. Preserve a short bounded close-reply flush before dropping the transport, independently of native/durable cleanup; require a Close reply in the regression. Installed tokio-tungstenite/tungstenite 0.29.0 returns the incoming Close with its automatic reply still queued (protocol/mod.rs:245, :475, :737). This branch never polls the source again or explicitly flushes the sink, and aborts the writer that could flush it. Thus graceful close is not guaranteed; the regression accepts an error or EOF as success. This is a protocol/interoperability limitation, not a cleanup or authorization bypass. The old teardown also lacked an explicit reply flush; the immediate abort removes any opportunity for queued writer work to flush it.

The minor is supported by the installed dependency source and RFC 6455 §5.5.1, which requires a reply to an incoming Close. Axum's Message documentation distinguishes an unclean drop from graceful close. It does not block this narrowly requested review.

Previous three majors:

  • Fixed — restored/suspended document dispatch. page-lifecycle.ts:12 synchronously latches suspension on pagehide, before restored visibility can start polling. Persisted pageshow keeps the latch set while requesting reload. api.ts:24 checks it before fetch, after fetch, after recovery and after reading JSON. The visible poller shares that guard. The original pre-pageshow request ordering and work after reload is requested are both fenced.
  • Fixed — recovery completing after pagehide. stream-attachment.svelte.ts:178 and subsequent continuation checks cover refresh and connection awaits; ensureConnected/getClient also guard entry. Pagehide permanently closes the owned StreamClient, whose token/ticket/body continuations check permanent closure. No replacement ticket/socket is dispatched by the retained suspended-document recovery path.
  • Fixed — sign-out during peer wait. auth.svelte.ts:198 checks the epoch captured before the lock/wait; a missing peer returns false instead of falling through into a fresh-epoch refresh. :290 sets signedOut and increments the epoch before preference flushing and wakes waiters. In-flight refresh responses and account responses check their captured epoch. Peer announcements cannot re-enter a signed-out document. Session clear retires the stream, clears registrations/retry timers and ignores old transport/channel callbacks.

Server review:

  • Peer Close still falls through to teardown_connection (stream.rs:1205): stop/join watcher, collect attachment IDs, shutdown native pairs, join the aborted writer, then bounded durable detaches. storage/mod.rs:2303 commits detach state and actor-attributed stream.session.detach audit in the same transaction, keyed by attachment ID. Existing timeout/rollback behavior remains; aborting the writer does not cancel those operations.
  • The revocation watcher and priority writer are unchanged by this diff. Typed forbidden CLOSEs are constructed after their durable audit, use the independent revocation queue and retain the C+850 ms/watchdog path. Immediate writer abort is only selected after an actual inbound peer Close; authorization withdrawal alone does not select it.
  • Only the exact outstanding eight-byte control-Ping payload clears pending state; wrong/unsolicited Pongs cannot satisfy it. This matches RFC 6455 §5.5.3. One outstanding heartbeat bounds state. Nonce allocation occurs on the heartbeat timer, not DATA frames; no new DATA-frame lookup, allocation, copying or lock is introduced.
  • Protocol PING/PONG handling and the 45 s receive-idle check remain. Control Pongs are received messages and update last_received, so they can reset receive-idle and suppress an otherwise-idle protocol Ping; protocol PINGs received from the client still get binary PONGs. A completely silent peer now closes earlier (15 s control Ping + 10 s deadline), as specified in contracts §3.10. The timer starts when Ping is queued, not when the socket flushes; the 10 s limit is therefore a queued-heartbeat bound under backpressure, not a measured wire RTT. Ping intervals are scheduled 15 s after matching Pong receipt.

Scope/skills: loaded emil-design-eng and all seven requested better-* skills. Applied evidence over taste, change-scoped/read-only review, explicit coverage limits, and recovery-copy consistency. Visual layout, typography, color, motion and rendered accessibility were not reviewed by this correctness/security job. No browser screenshots, Safari/iOS checks or perf-VM measurements were taken; no claims of visual or performance certification. Read CLAUDE.md and the requested decision/design/plan/UI/contracts context. Graph absent initially; rebuild initiated into this job's external artifact directory, with raw reads filling its unavailable coverage.

Verification results follow below.

All requested suites passed (debug builds, inherited RUSTC_WRAPPER=/home/kayg/.local/bin/sccache, SCCACHE_DIR=/mnt/hdd/infraternal/sccache, isolated CARGO_TARGET_DIR=/home/kayg/.cache/infraternal-targets/review-ship-ui).

nice -n 15 cargo test -p infraternal-server --lib stream:: -- --test-threads=1 — exit 0:

test result: ok. 69 passed; 0 failed; 0 ignored; 0 measured; 105 filtered out; finished in 18.14s

nice -n 15 cargo test -p infraternal-server --test stream_regressions -- --include-ignored --nocapture --test-threads=1 — exit 0, including real Docker/rootless Podman cases:

test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 134.01s

The existing real persistent-session peer-close case (close_requires_started_and_completion_audits) reached durable detached state before exercising audited termination. Real grant-shrink tests, stalled-stdin forbidden CLOSE tests and the new no-Pong deadline/peer-close tests passed. The new peer-close test alone opens no engine stream, so its name must not be interpreted as direct evidence of slow native cleanup; the teardown unit cases and persistent-session regressions supply complementary coverage.

nice -n 15 bun run --cwd packages/web test --maxWorkers=1 --testTimeout=30000 --hookTimeout=30000 — exit 0:

 Test Files  13 passed (13)
      Tests  75 passed (75)
   Start at  08:14:13
   Duration  7.39s (tests 44%, transform 39%, import 14%, worker 2%)

Prerequisite results, preserved rather than hidden: initial Vitest invocation exited 127 (vitest: command not found); bun install --frozen-lockfile succeeded without lockfile changes. Initial stream-unit build exited 101 (embedded web build missing; run scripts/build-web first); scripts/build-web succeeded, then stream-unit rerun passed. No fake embedded assets were used. Full logs: vitest.log, server-stream-first.log, server-stream.log, stream-regressions.log, install.log, build-web.log in this job directory.

The external graph rebuild completed: 438 files, 6,639 nodes and 94,740 edges; graph queries confirmed the reviewed auth/recovery/cleanup symbols and locations. Worktree remains clean and HEAD unchanged. This job ran no scripts/verify tier, especially no verify merge, and does not replace production-browser/merge/performance gates.

Verdict: **merge** (correctness/security review of the requested scope; not the required merge gate). Reviewed detached HEAD `1dd62b854fbdedadd9611c07b5bf19cd067cf9ae` against dev `ea776ea`, including `git diff ea776ea...1dd62b8` for the auth/stream paths and `git diff ea776ea 1dd62b8 -- crates/server`. No blocker or major found. No source edits, commits or pushes. | Severity | Location | Before | After / recommendation | Evidence and impact | | --- | --- | --- | --- | --- | | Minor | `crates/server/src/stream.rs:1159`; `crates/server/tests/stream_regressions.rs:249` | Receiving peer Close now drops the source and aborts the writer immediately. | Preserve a short bounded close-reply flush before dropping the transport, independently of native/durable cleanup; require a Close reply in the regression. | Installed tokio-tungstenite/tungstenite 0.29.0 returns the incoming Close with its automatic reply still queued (`protocol/mod.rs:245`, `:475`, `:737`). This branch never polls the source again or explicitly flushes the sink, and aborts the writer that could flush it. Thus graceful close is not guaranteed; the regression accepts an error or EOF as success. This is a protocol/interoperability limitation, not a cleanup or authorization bypass. The old teardown also lacked an explicit reply flush; the immediate abort removes any opportunity for queued writer work to flush it. | The minor is supported by the installed dependency source and [RFC 6455 §5.5.1](https://www.rfc-editor.org/rfc/rfc6455.html#section-5.5.1), which requires a reply to an incoming Close. [Axum's Message documentation](https://docs.rs/axum/0.8.9/axum/extract/ws/enum.Message.html#variant.Close) distinguishes an unclean drop from graceful close. It does not block this narrowly requested review. Previous three majors: - **Fixed — restored/suspended document dispatch.** `page-lifecycle.ts:12` synchronously latches suspension on pagehide, before restored visibility can start polling. Persisted pageshow keeps the latch set while requesting reload. `api.ts:24` checks it before fetch, after fetch, after recovery and after reading JSON. The visible poller shares that guard. The original pre-pageshow request ordering and work after reload is requested are both fenced. - **Fixed — recovery completing after pagehide.** `stream-attachment.svelte.ts:178` and subsequent continuation checks cover refresh and connection awaits; ensureConnected/getClient also guard entry. Pagehide permanently closes the owned StreamClient, whose token/ticket/body continuations check permanent closure. No replacement ticket/socket is dispatched by the retained suspended-document recovery path. - **Fixed — sign-out during peer wait.** `auth.svelte.ts:198` checks the epoch captured before the lock/wait; a missing peer returns false instead of falling through into a fresh-epoch refresh. `:290` sets signedOut and increments the epoch before preference flushing and wakes waiters. In-flight refresh responses and account responses check their captured epoch. Peer announcements cannot re-enter a signed-out document. Session clear retires the stream, clears registrations/retry timers and ignores old transport/channel callbacks. Server review: - Peer Close still falls through to `teardown_connection` (`stream.rs:1205`): stop/join watcher, collect attachment IDs, shutdown native pairs, join the aborted writer, then bounded durable detaches. `storage/mod.rs:2303` commits detach state and actor-attributed `stream.session.detach` audit in the same transaction, keyed by attachment ID. Existing timeout/rollback behavior remains; aborting the writer does not cancel those operations. - The revocation watcher and priority writer are unchanged by this diff. Typed forbidden CLOSEs are constructed after their durable audit, use the independent revocation queue and retain the C+850 ms/watchdog path. Immediate writer abort is only selected after an actual inbound peer Close; authorization withdrawal alone does not select it. - Only the exact outstanding eight-byte control-Ping payload clears pending state; wrong/unsolicited Pongs cannot satisfy it. This matches [RFC 6455 §5.5.3](https://www.rfc-editor.org/rfc/rfc6455.html#section-5.5.3). One outstanding heartbeat bounds state. Nonce allocation occurs on the heartbeat timer, not DATA frames; no new DATA-frame lookup, allocation, copying or lock is introduced. - Protocol PING/PONG handling and the 45 s receive-idle check remain. Control Pongs are received messages and update last_received, so they can reset receive-idle and suppress an otherwise-idle protocol Ping; protocol PINGs received from the client still get binary PONGs. A completely silent peer now closes earlier (15 s control Ping + 10 s deadline), as specified in contracts §3.10. The timer starts when Ping is queued, not when the socket flushes; the 10 s limit is therefore a queued-heartbeat bound under backpressure, not a measured wire RTT. Ping intervals are scheduled 15 s after matching Pong receipt. Scope/skills: loaded emil-design-eng and all seven requested better-* skills. Applied evidence over taste, change-scoped/read-only review, explicit coverage limits, and recovery-copy consistency. Visual layout, typography, color, motion and rendered accessibility were not reviewed by this correctness/security job. No browser screenshots, Safari/iOS checks or perf-VM measurements were taken; no claims of visual or performance certification. Read CLAUDE.md and the requested decision/design/plan/UI/contracts context. Graph absent initially; rebuild initiated into this job's external artifact directory, with raw reads filling its unavailable coverage. Verification results follow below. All requested suites passed (debug builds, inherited `RUSTC_WRAPPER=/home/kayg/.local/bin/sccache`, `SCCACHE_DIR=/mnt/hdd/infraternal/sccache`, isolated `CARGO_TARGET_DIR=/home/kayg/.cache/infraternal-targets/review-ship-ui`). `nice -n 15 cargo test -p infraternal-server --lib stream:: -- --test-threads=1` — exit 0: ```text test result: ok. 69 passed; 0 failed; 0 ignored; 0 measured; 105 filtered out; finished in 18.14s ``` `nice -n 15 cargo test -p infraternal-server --test stream_regressions -- --include-ignored --nocapture --test-threads=1` — exit 0, including real Docker/rootless Podman cases: ```text test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 134.01s ``` The existing real persistent-session peer-close case (`close_requires_started_and_completion_audits`) reached durable detached state before exercising audited termination. Real grant-shrink tests, stalled-stdin forbidden CLOSE tests and the new no-Pong deadline/peer-close tests passed. The new peer-close test alone opens no engine stream, so its name must not be interpreted as direct evidence of slow native cleanup; the teardown unit cases and persistent-session regressions supply complementary coverage. `nice -n 15 bun run --cwd packages/web test --maxWorkers=1 --testTimeout=30000 --hookTimeout=30000` — exit 0: ```text Test Files 13 passed (13) Tests 75 passed (75) Start at 08:14:13 Duration 7.39s (tests 44%, transform 39%, import 14%, worker 2%) ``` Prerequisite results, preserved rather than hidden: initial Vitest invocation exited 127 (`vitest: command not found`); `bun install --frozen-lockfile` succeeded without lockfile changes. Initial stream-unit build exited 101 (`embedded web build missing; run scripts/build-web first`); `scripts/build-web` succeeded, then stream-unit rerun passed. No fake embedded assets were used. Full logs: `vitest.log`, `server-stream-first.log`, `server-stream.log`, `stream-regressions.log`, `install.log`, `build-web.log` in this job directory. The external graph rebuild completed: 438 files, 6,639 nodes and 94,740 edges; graph queries confirmed the reviewed auth/recovery/cleanup symbols and locations. Worktree remains clean and HEAD unchanged. This job ran no scripts/verify tier, especially no verify merge, and does not replace production-browser/merge/performance gates.
Author
Owner

Starting ws-close-reply on branch ws-close-reply, base head 1dd62b854fbdedadd9611c07b5bf19cd067cf9ae.

I’m tracing the peer-close retirement path and its regression, then will add a bounded Close-reply flush without coupling it to session cleanup. Planned verification: server stream tests, stream_regressions, then INFRATERAL_VERIFY_RUN_ID=ws-close-reply scripts/verify fast.

Starting ws-close-reply on branch `ws-close-reply`, base head `1dd62b854fbdedadd9611c07b5bf19cd067cf9ae`. I’m tracing the peer-close retirement path and its regression, then will add a bounded Close-reply flush without coupling it to session cleanup. Planned verification: server stream tests, `stream_regressions`, then `INFRATERAL_VERIFY_RUN_ID=ws-close-reply scripts/verify fast`.
Author
Owner

Finding confirmed in the exact locked dependency: Cargo.lock pins tokio-tungstenite and tungstenite 0.29.0. tungstenite::WebSocket::read documents that reading queues automatic Close responses and the next read/write/flush writes them; its close-handshake guidance says to keep driving the socket until ConnectionClosed. RFC 6455 §5.5.1 requires a reply to a received Close frame.

I added one extra read-half poll, bounded to 100 ms, before the peer-close path drops the source and aborts the writer. The existing transport retirement still precedes native and durable session cleanup. The regression now succeeds only after receiving Message::Close; EOF and read errors fail it.

Sources: https://docs.rs/tungstenite/0.29.0/src/tungstenite/protocol/mod.rs.html and https://www.rfc-editor.org/rfc/rfc6455#section-5.5.1

Finding confirmed in the exact locked dependency: Cargo.lock pins `tokio-tungstenite` and `tungstenite` 0.29.0. `tungstenite::WebSocket::read` documents that reading queues automatic Close responses and the next read/write/flush writes them; its close-handshake guidance says to keep driving the socket until `ConnectionClosed`. RFC 6455 §5.5.1 requires a reply to a received Close frame. I added one extra read-half poll, bounded to 100 ms, before the peer-close path drops the source and aborts the writer. The existing transport retirement still precedes native and durable session cleanup. The regression now succeeds only after receiving `Message::Close`; EOF and read errors fail it. Sources: https://docs.rs/tungstenite/0.29.0/src/tungstenite/protocol/mod.rs.html and https://www.rfc-editor.org/rfc/rfc6455#section-5.5.1
Author
Owner

Finished ws-close-reply on branch ws-close-reply.

Head: 2fae616b9f06ceed40d8cd270b58a6a3402799ec

crates/server/src/stream.rs:1160 gives tungstenite a second read-half poll, bounded at 100 ms, before dropping the transport. Native and durable cleanup still starts afterward. crates/server/tests/stream_regressions.rs:255 now requires a Message::Close; EOF and read errors fail the regression.

The relevant dependency behavior is documented in tungstenite 0.29.0 source; RFC 6455 §5.5.1 requires a Close reply: https://www.rfc-editor.org/rfc/rfc6455#section-5.5.1.

Tests passed with debug info enabled and the worktree sccache preset:

  • cargo test -p infraternal-server --lib stream:: -- --test-threads=1 — cargo test: 69 passed, 105 filtered out (1 suite, 15.44s).
  • cargo test -p infraternal-server --test stream_regressions -- --include-ignored --nocapture --test-threads=1 — cargo test: 24 passed (1 suite, 125.77s).

CARGO_PROFILE_DEV_DEBUG=2 CARGO_PROFILE_TEST_DEBUG=2 INFRATERAL_VERIFY_RUN_ID=ws-close-reply scripts/verify fast exited 0. Stage output (verbatim):

PASS fast: migrations are append-only (0.199s)
PASS fast: workspace package dependencies (0.261s)
PASS fast: gate target-directory and launch diagnostics tests (0.310s)
PASS fast: JavaScript dependencies (1.267s)
SUPPLY_CHAIN_REVIEWS advisory exceptions are within their review windows
SUPPLY_CHAIN cargo-deny: cargo-deny 0.20.2
SUPPLY_CHAIN_NOTICES generated THIRD_PARTY_NOTICES.md from 81 frontend packages
SUPPLY_CHAIN_NOTICES copied source: 47 calternal-derived files
SUPPLY_CHAIN_NOTICES license files: 54 distinct texts; 0 packages need manual license review
advisories ok
SUPPLY_CHAIN_RUST_ADVISORIES passed with refreshed advisory data
licenses ok
SUPPLY_CHAIN_RUST_LICENSES passed
SUPPLY_CHAIN_BUN_AUDIT findings reported; this check is report-only
SUPPLY_CHAIN_PASS Rust advisory/license checks complete; Bun findings are report-only
PASS fast: supply-chain checks (4.127s)
PASS fast: build web app (8.416s)
PASS fast: cargo fmt --check (1.662s)
PASS fast: cargo clippy (92.607s)
PASS fast: cargo test (318.099s)
PASS fast: svelte-check (32.951s)
PASS fast: UI package svelte-check (6.131s)
PASS fast: stream package typecheck (5.679s)
PASS fast: Vitest (20.735s)
PASS fast: UI package Vitest (6.609s)
PASS fast: stream package Vitest (0.999s)
PASS fast: OpenAPI and TypeScript client drift (75.549s)
PASS fast: terminal TypeScript (2.578s)
PASS fast: terminal Vitest (1.437s)
Finished ws-close-reply on branch `ws-close-reply`. Head: `2fae616b9f06ceed40d8cd270b58a6a3402799ec` `crates/server/src/stream.rs:1160` gives tungstenite a second read-half poll, bounded at 100 ms, before dropping the transport. Native and durable cleanup still starts afterward. `crates/server/tests/stream_regressions.rs:255` now requires a `Message::Close`; EOF and read errors fail the regression. The relevant dependency behavior is documented in [tungstenite 0.29.0 source](https://docs.rs/tungstenite/0.29.0/src/tungstenite/protocol/mod.rs.html); RFC 6455 §5.5.1 requires a Close reply: https://www.rfc-editor.org/rfc/rfc6455#section-5.5.1. Tests passed with debug info enabled and the worktree sccache preset: - `cargo test -p infraternal-server --lib stream:: -- --test-threads=1` — `cargo test: 69 passed, 105 filtered out (1 suite, 15.44s)`. - `cargo test -p infraternal-server --test stream_regressions -- --include-ignored --nocapture --test-threads=1` — `cargo test: 24 passed (1 suite, 125.77s)`. `CARGO_PROFILE_DEV_DEBUG=2 CARGO_PROFILE_TEST_DEBUG=2 INFRATERAL_VERIFY_RUN_ID=ws-close-reply scripts/verify fast` exited 0. Stage output (verbatim): ```text PASS fast: migrations are append-only (0.199s) PASS fast: workspace package dependencies (0.261s) PASS fast: gate target-directory and launch diagnostics tests (0.310s) PASS fast: JavaScript dependencies (1.267s) SUPPLY_CHAIN_REVIEWS advisory exceptions are within their review windows SUPPLY_CHAIN cargo-deny: cargo-deny 0.20.2 SUPPLY_CHAIN_NOTICES generated THIRD_PARTY_NOTICES.md from 81 frontend packages SUPPLY_CHAIN_NOTICES copied source: 47 calternal-derived files SUPPLY_CHAIN_NOTICES license files: 54 distinct texts; 0 packages need manual license review advisories ok SUPPLY_CHAIN_RUST_ADVISORIES passed with refreshed advisory data licenses ok SUPPLY_CHAIN_RUST_LICENSES passed SUPPLY_CHAIN_BUN_AUDIT findings reported; this check is report-only SUPPLY_CHAIN_PASS Rust advisory/license checks complete; Bun findings are report-only PASS fast: supply-chain checks (4.127s) PASS fast: build web app (8.416s) PASS fast: cargo fmt --check (1.662s) PASS fast: cargo clippy (92.607s) PASS fast: cargo test (318.099s) PASS fast: svelte-check (32.951s) PASS fast: UI package svelte-check (6.131s) PASS fast: stream package typecheck (5.679s) PASS fast: Vitest (20.735s) PASS fast: UI package Vitest (6.609s) PASS fast: stream package Vitest (0.999s) PASS fast: OpenAPI and TypeScript client drift (75.549s) PASS fast: terminal TypeScript (2.578s) PASS fast: terminal Vitest (1.437s) ```
Author
Owner

Job install-timeline-ui started on branch install-timeline-ui at base a3c0d13 (the agent-install contract commit). Scope is the managed-host add flow, setup timeline, typed-client integration, Vitest coverage, and owned browser checks under packages/web/** and packages/ui/**; no backend or SSH-target setup changes.

Job install-timeline-ui started on branch `install-timeline-ui` at base `a3c0d13` (the agent-install contract commit). Scope is the managed-host add flow, setup timeline, typed-client integration, Vitest coverage, and owned browser checks under `packages/web/**` and `packages/ui/**`; no backend or SSH-target setup changes.
Author
Owner

Finding: the merged agent-install branch adds the typed create/status/trust/retry contract and server implementation, but the generated client has no enrolled-infraternal-agent collection endpoint. packages/api-client/src/schema.ts exposes POST /api/v1/agents/enroll, POST /api/v1/agents/join-tokens, POST /api/v1/agents/me/certificate, and DELETE /api/v1/agents/{agent_id} only. Therefore the UI cannot safely populate the requested “via an enrolled infraternal agent” selector from this contract. The managed-host flow currently uses the typed server-install-key path; no untyped or guessed list request will be added.

Finding: the merged `agent-install` branch adds the typed create/status/trust/retry contract and server implementation, but the generated client has no enrolled-infraternal-agent collection endpoint. `packages/api-client/src/schema.ts` exposes POST `/api/v1/agents/enroll`, POST `/api/v1/agents/join-tokens`, POST `/api/v1/agents/me/certificate`, and DELETE `/api/v1/agents/{agent_id}` only. Therefore the UI cannot safely populate the requested “via an enrolled infraternal agent” selector from this contract. The managed-host flow currently uses the typed server-install-key path; no untyped or guessed list request will be added.
Author
Owner

Browser verification finding: INFRATERMINAL_VERIFY_RUN_ID=install-timeline-ui-browser scripts/verify browser built the production web bundle and release binary, installed Chromium, then stopped before the production-server browser suite because the unrelated terminal fixture test xterm: bounds an outrunning producer and reports consumption timed out at its 60-second Playwright limit. The fixture run reported 36/37 passing after 200.697 seconds; its page snapshot contained the 4 MiB terminal output used by the backpressure case. The VM load was 33.51 at gate start (8 online CPUs) and 29.56 at investigation; no files under packages/terminal are changed in this worktree. I will retry the gate if the VM load drops enough for a representative run.

Browser verification finding: `INFRATERMINAL_VERIFY_RUN_ID=install-timeline-ui-browser scripts/verify browser` built the production web bundle and release binary, installed Chromium, then stopped before the production-server browser suite because the unrelated terminal fixture test `xterm: bounds an outrunning producer and reports consumption` timed out at its 60-second Playwright limit. The fixture run reported 36/37 passing after 200.697 seconds; its page snapshot contained the 4 MiB terminal output used by the backpressure case. The VM load was 33.51 at gate start (8 online CPUs) and 29.56 at investigation; no files under `packages/terminal` are changed in this worktree. I will retry the gate if the VM load drops enough for a representative run.
Author
Owner

Backend integration finding after fast-forwarding agent-install to e6df34e: crates/server/src/install.rs currently registers only GET /api/v1/hosts/install/public-key; the create, status, trust and retry handlers remain empty declarations (create() {}, status() {}, trust() {}, retry() {}). The typed client contract is available, so the UI/controller and fake-client tests are built against it, but a real install cannot be submitted or resumed until those handlers are implemented and registered. The enrolled-infraternal-agent collection endpoint is also still absent from the generated client.

Backend integration finding after fast-forwarding `agent-install` to `e6df34e`: `crates/server/src/install.rs` currently registers only `GET /api/v1/hosts/install/public-key`; the create, status, trust and retry handlers remain empty declarations (`create() {}`, `status() {}`, `trust() {}`, `retry() {}`). The typed client contract is available, so the UI/controller and fake-client tests are built against it, but a real install cannot be submitted or resumed until those handlers are implemented and registered. The enrolled-infraternal-agent collection endpoint is also still absent from the generated client.
Author
Owner

Production browser perf finding and fix: the initial retry failed the existing container-detail cold JavaScript budget at 120,857 bytes versus the 117,760-byte cap. Inspection of the built production chunks found the new HostInstallTimeline markup inside the shared _CmrdUjYb.js chunk, which container detail downloads, because the host setup flow imported it from the @infraternal/ui root barrel. I isolated it as the @infraternal/ui/host-install-timeline subpath and updated the flow import; the rebuilt output now places its markup in a separate chunk (BVZRP5Li.js) outside the container route's static imports. Focused verification passed: web Svelte check 0 errors/warnings; UI Svelte check 0 errors/warnings; web Vitest 25/25; UI Vitest 4/4. Production browser gate rerun pending.

Production browser perf finding and fix: the initial retry failed the existing container-detail cold JavaScript budget at 120,857 bytes versus the 117,760-byte cap. Inspection of the built production chunks found the new HostInstallTimeline markup inside the shared `_CmrdUjYb.js` chunk, which container detail downloads, because the host setup flow imported it from the `@infraternal/ui` root barrel. I isolated it as the `@infraternal/ui/host-install-timeline` subpath and updated the flow import; the rebuilt output now places its markup in a separate chunk (`BVZRP5Li.js`) outside the container route's static imports. Focused verification passed: web Svelte check 0 errors/warnings; UI Svelte check 0 errors/warnings; web Vitest 25/25; UI Vitest 4/4. Production browser gate rerun pending.
Author
Owner

Starting ssh-web-setup2 on branch ssh-web-setup, base head 1dd62b854fbdedadd9611c07b5bf19cd067cf9ae. I am reviewing the existing uncommitted SSH web setup work, then running the required frontend checks before committing.

Starting ssh-web-setup2 on branch `ssh-web-setup`, base head `1dd62b854fbdedadd9611c07b5bf19cd067cf9ae`. I am reviewing the existing uncommitted SSH web setup work, then running the required frontend checks before committing.
Author
Owner

The production-browser run reached the SSH setup flow and passed host-key probe/trust, but opening the first terminal to 127.0.0.1:2222 failed: the stream returned ssh_error with details.stage=auth. The failure occurred before screenshots; I am checking the real test sshd's authorized-keys setup and server evidence before changing anything.

The production-browser run reached the SSH setup flow and passed host-key probe/trust, but opening the first terminal to `127.0.0.1:2222` failed: the stream returned `ssh_error` with `details.stage=auth`. The failure occurred before screenshots; I am checking the real test sshd's authorized-keys setup and server evidence before changing anything.
Author
Owner

The failure is in the changed-key browser fixture, not the product terminal path: the first connection to the real sshtarget sshd succeeded (the sshd journal recorded accepted public-key logins), but the rotated-key fixture's AuthorizedKeysFile was under /tmp. A matching rootless OpenSSH reproduction reported Authentication refused: bad ownership or modes for directory /tmp with StrictModes yes. I moved that private fixture under XDG_RUNTIME_DIR (home fallback), whose parent directories are not world-writable.

The failure is in the changed-key browser fixture, not the product terminal path: the first connection to the real `sshtarget` sshd succeeded (the sshd journal recorded accepted public-key logins), but the rotated-key fixture's `AuthorizedKeysFile` was under `/tmp`. A matching rootless OpenSSH reproduction reported `Authentication refused: bad ownership or modes for directory /tmp` with `StrictModes yes`. I moved that private fixture under `XDG_RUNTIME_DIR` (home fallback), whose parent directories are not world-writable.
Author
Owner

After relocating the private fixture, the SSH flow completed key rotation and the second terminal opened; all four SSH screenshots were written. The browser run then failed only on its local console assertion, which collected six Chromium Failed to load resource messages for HTTP 404/502/503 responses while the host-detail fallback and absent-SSH-settings reads were handled. I am narrowing the harness exception to those documented read paths; the SSH POST/probe/terminal response assertions remain strict.

After relocating the private fixture, the SSH flow completed key rotation and the second terminal opened; all four SSH screenshots were written. The browser run then failed only on its local console assertion, which collected six Chromium `Failed to load resource` messages for HTTP 404/502/503 responses while the host-detail fallback and absent-SSH-settings reads were handled. I am narrowing the harness exception to those documented read paths; the SSH POST/probe/terminal response assertions remain strict.
Author
Owner

The production container-detail cold-route JavaScript gzip measurement exceeded the 120 KiB budget with the new timeline exposed through the shared UI barrel. Moving the timeline to a dedicated package subpath reduced the measured route bundle, and isolating SegmentedControl/TabBar from the root barrel brought it to 116,275 bytes (1,485 bytes under the 117,760-byte cap). The app-shell and container route now load those interactive primitives only through dedicated subpaths where needed.

The production container-detail cold-route JavaScript gzip measurement exceeded the 120 KiB budget with the new timeline exposed through the shared UI barrel. Moving the timeline to a dedicated package subpath reduced the measured route bundle, and isolating SegmentedControl/TabBar from the root barrel brought it to 116,275 bytes (1,485 bytes under the 117,760-byte cap). The app-shell and container route now load those interactive primitives only through dedicated subpaths where needed.
Author
Owner

Browser result: PASS SSH host setup browser flow: fixed sshd, key copy, settings update, first trust, terminal, changed-key replacement. The run then failed later at the existing container cold-JavaScript budget: 119310 bytes versus the 117760-byte maximum. Earlier browser notes already recorded 119309 bytes on this worktree before this step, so I left that unrelated size issue out of scope. The four requested screenshots were rewritten under /mnt/hdd/infraternal/artifacts/ssh-web-setup/.

Browser result: `PASS SSH host setup browser flow: fixed sshd, key copy, settings update, first trust, terminal, changed-key replacement`. The run then failed later at the existing container cold-JavaScript budget: 119310 bytes versus the 117760-byte maximum. Earlier browser notes already recorded 119309 bytes on this worktree before this step, so I left that unrelated size issue out of scope. The four requested screenshots were rewritten under `/mnt/hdd/infraternal/artifacts/ssh-web-setup/`.
Author
Owner

Finished on branch ssh-web-setup at head c7c84ae0d870b253548d50514492e4e8b99a90d0.

INFRATERNAL_VERIFY_RUN_ID=ssh-web-setup2 scripts/verify fast exited 0. Its gate output:

PASS fast: migrations are append-only (0.145s)
PASS fast: workspace package dependencies (0.255s)
PASS fast: gate target-directory and launch diagnostics tests (0.425s)
PASS fast: JavaScript dependencies (0.004s)
PASS fast: advisory review policy tests (0.173s)
PASS fast: supply-chain checks (4.507s)
PASS fast: build web app (7.334s)
PASS fast: cargo fmt --check (1.363s)
PASS fast: cargo clippy (161.280s)
PASS fast: cargo test (235.626s)
PASS fast: svelte-check (12.500s)
PASS fast: UI package svelte-check (4.853s)
PASS fast: stream package typecheck (5.172s)
PASS fast: Vitest (4.084s)
PASS fast: UI package Vitest (6.696s)
PASS fast: stream package Vitest (1.023s)
PASS fast: OpenAPI and TypeScript client drift (47.312s)
PASS fast: terminal TypeScript (2.402s)
PASS fast: terminal Vitest (1.331s)

The real-sshd flow output was:

PASS SSH host setup browser flow: fixed sshd, key copy, settings update, first trust, terminal, changed-key replacement
FAIL browser: Playwright against release server (41.825s)
METRIC container-detail JS gzip before terminal: 119310 bytes

The enclosing browser gate stopped at the existing container cold-JavaScript budget (maximum 117760 bytes). Earlier run notes recorded the same overage before this step. The four screenshots are saved under /mnt/hdd/infraternal/artifacts/ssh-web-setup/.

Leftovers: a host removal action is not exposed in the web UI; the saved worktree diff did not include one, so it remains follow-up scope. No browser run was attempted for removal.

Finished on branch `ssh-web-setup` at head `c7c84ae0d870b253548d50514492e4e8b99a90d0`. `INFRATERNAL_VERIFY_RUN_ID=ssh-web-setup2 scripts/verify fast` exited 0. Its gate output: ```text PASS fast: migrations are append-only (0.145s) PASS fast: workspace package dependencies (0.255s) PASS fast: gate target-directory and launch diagnostics tests (0.425s) PASS fast: JavaScript dependencies (0.004s) PASS fast: advisory review policy tests (0.173s) PASS fast: supply-chain checks (4.507s) PASS fast: build web app (7.334s) PASS fast: cargo fmt --check (1.363s) PASS fast: cargo clippy (161.280s) PASS fast: cargo test (235.626s) PASS fast: svelte-check (12.500s) PASS fast: UI package svelte-check (4.853s) PASS fast: stream package typecheck (5.172s) PASS fast: Vitest (4.084s) PASS fast: UI package Vitest (6.696s) PASS fast: stream package Vitest (1.023s) PASS fast: OpenAPI and TypeScript client drift (47.312s) PASS fast: terminal TypeScript (2.402s) PASS fast: terminal Vitest (1.331s) ``` The real-sshd flow output was: ```text PASS SSH host setup browser flow: fixed sshd, key copy, settings update, first trust, terminal, changed-key replacement FAIL browser: Playwright against release server (41.825s) METRIC container-detail JS gzip before terminal: 119310 bytes ``` The enclosing browser gate stopped at the existing container cold-JavaScript budget (maximum 117760 bytes). Earlier run notes recorded the same overage before this step. The four screenshots are saved under `/mnt/hdd/infraternal/artifacts/ssh-web-setup/`. Leftovers: a host removal action is not exposed in the web UI; the saved worktree diff did not include one, so it remains follow-up scope. No browser run was attempted for removal.
Author
Owner

Browser evidence from install-timeline-ui-browser-final4: the production route overflow check failed on /hosts at 320px. The Hosts grid ended at x=336 while its content box ended at x=320; the two always-visible mobile columns required 12rem + 8rem plus the 16px grid gap. Added narrower mobile tracks for Host and Status in packages/web/src/routes/hosts/+page.svelte. Web/UI Vitest suites pass (100/100 and 14/14); rerunning the browser tier to verify all route widths and the install-flow screenshot matrix.

Browser evidence from install-timeline-ui-browser-final4: the production route overflow check failed on `/hosts` at 320px. The Hosts grid ended at x=336 while its content box ended at x=320; the two always-visible mobile columns required 12rem + 8rem plus the 16px grid gap. Added narrower mobile tracks for Host and Status in `packages/web/src/routes/hosts/+page.svelte`. Web/UI Vitest suites pass (100/100 and 14/14); rerunning the browser tier to verify all route widths and the install-flow screenshot matrix.
Author
Owner

Browser evidence from install-timeline-ui-browser-final6: the new managed-host form and all five timeline states rendered and were captured at 1440x900 and 390x844 in both themes. The gate then stopped in its existing log-retention assertion: it expected “older log lines dropped”, while ContainerLogPanel.svelte and docs/UI.md now correctly say “older lines rolled off; showing the newest retained lines.” Updated only that stale browser expectation; rerunning the browser gate.

Browser evidence from install-timeline-ui-browser-final6: the new managed-host form and all five timeline states rendered and were captured at 1440x900 and 390x844 in both themes. The gate then stopped in its existing log-retention assertion: it expected “older log lines dropped”, while `ContainerLogPanel.svelte` and docs/UI.md now correctly say “older lines rolled off; showing the newest retained lines.” Updated only that stale browser expectation; rerunning the browser gate.
Author
Owner

Starting job #46 in branch branched-sidebar, base dev at 67dffa58513296c936c3909fd1999b85c37122a1.

Scope: sidebar/navigation tree in packages/web and packages/ui, owned tests and browser checks. I will not change Hosts page bodies. I am first reviewing the sidebar persistence, host/container/SSH inventory data, and the current production-browser workflow.

Starting job #46 in branch `branched-sidebar`, base `dev` at `67dffa58513296c936c3909fd1999b85c37122a1`. Scope: sidebar/navigation tree in `packages/web` and `packages/ui`, owned tests and browser checks. I will not change Hosts page bodies. I am first reviewing the sidebar persistence, host/container/SSH inventory data, and the current production-browser workflow.
Author
Owner

Evidence and implementation decision for #46:

  • HostSummary from GET /api/v1/hosts contains status (online/offline) and currently connected engine summaries, but no SSH-target flag or setting_up status. The existing typed GET /api/v1/hosts/{host_id}/ssh is the available target-presence check; 404 means that host has no SSH settings.
  • GET /api/v1/containers already accepts host and engine filters and its response is bounded by the existing inventory limits. I will derive Docker/Podman counts from one unfiltered response using the current ETag/2-second visible poll pattern, not fan out one list call per host.
  • packages/web/src/routes/containers/+page.svelte currently builds API filters only from local state and does not read URL search parameters. Tree URLs alone would not filter the page, so I will add the minimal incoming host/engine query handoff there; no Hosts page body will be edited.

SSH settings will be checked on host expansion through the typed client and cached for the session. The host status dot will preserve the API's online/offline status; Setting up is reserved for the temporary capability check on an online host with no reported engines.

Evidence and implementation decision for #46: - `HostSummary` from `GET /api/v1/hosts` contains status (`online`/`offline`) and currently connected engine summaries, but no SSH-target flag or `setting_up` status. The existing typed `GET /api/v1/hosts/{host_id}/ssh` is the available target-presence check; `404` means that host has no SSH settings. - `GET /api/v1/containers` already accepts `host` and `engine` filters and its response is bounded by the existing inventory limits. I will derive Docker/Podman counts from one unfiltered response using the current ETag/2-second visible poll pattern, not fan out one list call per host. - `packages/web/src/routes/containers/+page.svelte` currently builds API filters only from local state and does not read URL search parameters. Tree URLs alone would not filter the page, so I will add the minimal incoming `host`/`engine` query handoff there; no Hosts page body will be edited. SSH settings will be checked on host expansion through the typed client and cached for the session. The host status dot will preserve the API's online/offline status; `Setting up` is reserved for the temporary capability check on an online host with no reported engines.
Author
Owner

Finding/decision: the Infrastructure tree derives Docker/Podman LIVE counts from the existing bounded unfiltered container list and host engines from GET /api/v1/hosts. A real production-browser check now compares both counts to that API response, starts one additional real container per runtime to verify live refresh, and follows both host/engine branch filters. Empty-state screenshots use a temporary release server with --no-local-agent and a fresh database, so the empty host list is real rather than intercepted. Expansion is stored under a user-specific browser key; the API has no expansion preference field.

Finding/decision: the Infrastructure tree derives Docker/Podman LIVE counts from the existing bounded unfiltered container list and host engines from GET /api/v1/hosts. A real production-browser check now compares both counts to that API response, starts one additional real container per runtime to verify live refresh, and follows both host/engine branch filters. Empty-state screenshots use a temporary release server with --no-local-agent and a fresh database, so the empty host list is real rather than intercepted. Expansion is stored under a user-specific browser key; the API has no expansion preference field.
Author
Owner

Browser finding: the first production-browser run passed setup, SSH setup and the multi-tab flows, then stopped in the existing sidebar item-drag persistence check before reaching the new tree assertions. After dragging Hosts below Containers, the saved order remained [hosts, containers] instead of the expected [containers, hosts]. The shared VM was loaded; I am rerunning to separate a timing flake from a regression.

Browser finding: the first production-browser run passed setup, SSH setup and the multi-tab flows, then stopped in the existing sidebar item-drag persistence check before reaching the new tree assertions. After dragging Hosts below Containers, the saved order remained [hosts, containers] instead of the expected [containers, hosts]. The shared VM was loaded; I am rerunning to separate a timing flake from a regression.
Author
Owner

Browser finding: the production-browser rerun reproduced the sidebar drag issue under a fresh database. The baseline order was [hosts, containers]; after dragging Hosts below Containers the order remained [hosts, containers], so no arrangement PUT completed. I added DOM/order announcement diagnostics around the assertion and will use the next production run to identify whether the new tree region is affecting the DnD target.

Browser finding: the production-browser rerun reproduced the sidebar drag issue under a fresh database. The baseline order was [hosts, containers]; after dragging Hosts below Containers the order remained [hosts, containers], so no arrangement PUT completed. I added DOM/order announcement diagnostics around the assertion and will use the next production run to identify whether the new tree region is affecting the DnD target.
Author
Owner

Browser verification reached the terminal flood budget after the host install route, including all 24 requested form/timeline screenshots. The run failed only on fps=58.2524 against the existing fps < 60 budget; line rate, bounded retention, bytes, dropped count, and rendered row count passed. At the time, three concurrent Rust compiler processes were using about 90%, 97%, and 140% CPU, and host load average was 8.36. I will rerun the browser gate after that unrelated compile load settles; no budget or product threshold was changed.

Browser verification reached the terminal flood budget after the host install route, including all 24 requested form/timeline screenshots. The run failed only on `fps=58.2524` against the existing `fps < 60` budget; line rate, bounded retention, bytes, dropped count, and rendered row count passed. At the time, three concurrent Rust compiler processes were using about 90%, 97%, and 140% CPU, and host load average was 8.36. I will rerun the browser gate after that unrelated compile load settles; no budget or product threshold was changed.
Author
Owner

Starting install-timeline-ui2 on branch install-timeline-ui at head d89d22c910bc2fe102ac1f8d15eef7152efd0a66. I am checking the existing UI changes, then will merge dev at 0b4fc37, verify the host-install flow against the real test sshd, capture the requested timeline states, and run INFRATERAL_VERIFY_RUN_ID=install-timeline-ui2 scripts/verify fast.

Starting install-timeline-ui2 on branch `install-timeline-ui` at head `d89d22c910bc2fe102ac1f8d15eef7152efd0a66`. I am checking the existing UI changes, then will merge `dev` at `0b4fc37`, verify the host-install flow against the real test sshd, capture the requested timeline states, and run `INFRATERAL_VERIFY_RUN_ID=install-timeline-ui2 scripts/verify fast`.
Author
Owner

The default web Vitest run failed 4/101 tests across auth.test.ts and stream-attachment.test.ts (two 5-second timeouts and two load-sensitive assertions). These modules are outside this change. Rerunning each of the four failed tests alone with the package Vitest command passed all four; svelte-check found 0 errors and 0 warnings. I am recording this as a load-sensitive baseline and will report any verify fast retry separately.

The default web Vitest run failed 4/101 tests across `auth.test.ts` and `stream-attachment.test.ts` (two 5-second timeouts and two load-sensitive assertions). These modules are outside this change. Rerunning each of the four failed tests alone with the package Vitest command passed all four; `svelte-check` found 0 errors and 0 warnings. I am recording this as a load-sensitive baseline and will report any `verify fast` retry separately.
Author
Owner

Browser evidence on branched-sidebar (base dev 67dffa5): the production release browser flow reached the real Docker/Podman/SSH tree check and verified two filtered routes. Latest recorded values were Docker LIVE=7, Podman LIVE=3, and SSH targets=1. Host screenshots were captured at 1440x900 and 390x844 in light and dark themes under /mnt/hdd/infraternal/artifacts/branched-sidebar/.

Two limits surfaced. The no-host screenshots cannot be produced with the current server: Server::open always persists a local host, including with --no-local-agent, and the hosts API has no removal route. The production browser flow also stops at its existing container-detail cold-JS gate: 119414 gzip bytes versus the 117760-byte maximum. The owner’s baseline note is about 119.3 KB.

Browser evidence on branched-sidebar (base dev 67dffa5): the production release browser flow reached the real Docker/Podman/SSH tree check and verified two filtered routes. Latest recorded values were Docker LIVE=7, Podman LIVE=3, and SSH targets=1. Host screenshots were captured at 1440x900 and 390x844 in light and dark themes under /mnt/hdd/infraternal/artifacts/branched-sidebar/. Two limits surfaced. The no-host screenshots cannot be produced with the current server: Server::open always persists a local host, including with --no-local-agent, and the hosts API has no removal route. The production browser flow also stops at its existing container-detail cold-JS gate: 119414 gzip bytes versus the 117760-byte maximum. The owner’s baseline note is about 119.3 KB.
Author
Owner

Finished branched-sidebar #46.

Branch: branched-sidebar
Base: 67dffa58513296c936c3909fd1999b85c37122a1
Head: f76cbfa1ac895177df89aac37e53f5c6701a9f9f
Commits:

  • 7162df4 feat(web): add enterprise infrastructure tree sidebar
  • f76cbfa test(web): verify branched sidebar with live runtime inventory

The release-browser tree flow exercised real Docker and Podman inventory, SSH targets, branch navigation/filter parameters, count updates, and ArrowRight/ArrowLeft. It reported:

INFRASTRUCTURE_TREE Docker=... LIVE=7 Podman=... LIVE=3 SSH=... targets=1 filtered-routes=2

Host screenshots:

  • /mnt/hdd/infraternal/artifacts/branched-sidebar/infrastructure-hosts-light-1440x900.png
  • /mnt/hdd/infraternal/artifacts/branched-sidebar/infrastructure-hosts-dark-1440x900.png
  • /mnt/hdd/infraternal/artifacts/branched-sidebar/infrastructure-hosts-light-390x844.png
  • /mnt/hdd/infraternal/artifacts/branched-sidebar/infrastructure-hosts-dark-390x844.png

The no-host screenshots could not be produced authentically: Server::open persists a local host even with --no-local-agent, and the current hosts API has no removal route. I did not fake the inventory. The browser run later stopped at the existing cold JavaScript budget: 119,414 bytes against the 117,760-byte cap. The host tree interaction and screenshots had completed before that failure.

Required fast gate command:
RUSTC_WRAPPER=/home/kayg/.local/bin/sccache INFRATERAL_VERIFY_RUN_ID=branched-sidebar INFRATERNAL_VERIFY_RUN_ID=branched-sidebar scripts/verify fast

Gate output:

WARN load5=16.49 exceeds online CPU count=8; timing-sensitive checks may be delayed
PASS fast: migrations are append-only (0.261s)
PASS fast: workspace package dependencies (0.379s)
PASS fast: gate target-directory and launch diagnostics tests (0.397s)
PASS fast: JavaScript dependencies (0.128s)
PASS fast: advisory review policy tests (0.181s)
SUPPLY_CHAIN_REVIEWS advisory exceptions are within their review windows
SUPPLY_CHAIN cargo-deny: cargo-deny 0.20.2
SUPPLY_CHAIN_NOTICES generated THIRD_PARTY_NOTICES.md from 81 frontend packages
SUPPLY_CHAIN_NOTICES copied source: 47 calternal-derived files
SUPPLY_CHAIN_NOTICES license files: 54 distinct texts; 0 packages need manual license review
advisories ok
SUPPLY_CHAIN_RUST_ADVISORIES passed with refreshed advisory data
licenses ok
SUPPLY_CHAIN_RUST_LICENSES passed
bun audit v1.4.2 (744846f84)

cookie@0.6.0
  workspace:@infraternal/web > @sveltejs/kit > cookie
  low: cookie accepts cookie name, path, and domain with out of bounds characters (<0.7.0) - https://github.com/advisories/GHSA-pxg6-pf52-xh8x

1 vulnerability (1 low)

  bun audit fix           upgrade the vulnerable packages within their ranges
  bun audit fix --latest  upgrade the vulnerable packages across major versions
SUPPLY_CHAIN_BUN_AUDIT findings reported; this check is report-only
SUPPLY_CHAIN_PASS Rust advisory/license checks complete; Bun findings are report-only
PASS fast: supply-chain checks (8.531s)
PASS fast: build web app (25.669s)
PASS fast: cargo fmt --check (2.744s)
PASS fast: cargo clippy (591.579s)
PASS fast: cargo test (645.752s)
PASS fast: svelte-check (39.311s)
PASS fast: UI package svelte-check (12.983s)
PASS fast: stream package typecheck (15.891s)
PASS fast: Vitest (13.652s)
PASS fast: UI package Vitest (17.312s)
PASS fast: stream package Vitest (3.361s)
PASS fast: OpenAPI and TypeScript client drift (121.840s)
PASS fast: terminal TypeScript (6.290s)
PASS fast: terminal Vitest (2.847s)

Worktree is clean. No issue closure requested.

Finished branched-sidebar #46. Branch: `branched-sidebar` Base: `67dffa58513296c936c3909fd1999b85c37122a1` Head: `f76cbfa1ac895177df89aac37e53f5c6701a9f9f` Commits: - `7162df4 feat(web): add enterprise infrastructure tree sidebar` - `f76cbfa test(web): verify branched sidebar with live runtime inventory` The release-browser tree flow exercised real Docker and Podman inventory, SSH targets, branch navigation/filter parameters, count updates, and ArrowRight/ArrowLeft. It reported: ``` INFRASTRUCTURE_TREE Docker=... LIVE=7 Podman=... LIVE=3 SSH=... targets=1 filtered-routes=2 ``` Host screenshots: - `/mnt/hdd/infraternal/artifacts/branched-sidebar/infrastructure-hosts-light-1440x900.png` - `/mnt/hdd/infraternal/artifacts/branched-sidebar/infrastructure-hosts-dark-1440x900.png` - `/mnt/hdd/infraternal/artifacts/branched-sidebar/infrastructure-hosts-light-390x844.png` - `/mnt/hdd/infraternal/artifacts/branched-sidebar/infrastructure-hosts-dark-390x844.png` The no-host screenshots could not be produced authentically: `Server::open` persists a local host even with `--no-local-agent`, and the current hosts API has no removal route. I did not fake the inventory. The browser run later stopped at the existing cold JavaScript budget: 119,414 bytes against the 117,760-byte cap. The host tree interaction and screenshots had completed before that failure. Required fast gate command: `RUSTC_WRAPPER=/home/kayg/.local/bin/sccache INFRATERAL_VERIFY_RUN_ID=branched-sidebar INFRATERNAL_VERIFY_RUN_ID=branched-sidebar scripts/verify fast` Gate output: ``` WARN load5=16.49 exceeds online CPU count=8; timing-sensitive checks may be delayed PASS fast: migrations are append-only (0.261s) PASS fast: workspace package dependencies (0.379s) PASS fast: gate target-directory and launch diagnostics tests (0.397s) PASS fast: JavaScript dependencies (0.128s) PASS fast: advisory review policy tests (0.181s) SUPPLY_CHAIN_REVIEWS advisory exceptions are within their review windows SUPPLY_CHAIN cargo-deny: cargo-deny 0.20.2 SUPPLY_CHAIN_NOTICES generated THIRD_PARTY_NOTICES.md from 81 frontend packages SUPPLY_CHAIN_NOTICES copied source: 47 calternal-derived files SUPPLY_CHAIN_NOTICES license files: 54 distinct texts; 0 packages need manual license review advisories ok SUPPLY_CHAIN_RUST_ADVISORIES passed with refreshed advisory data licenses ok SUPPLY_CHAIN_RUST_LICENSES passed bun audit v1.4.2 (744846f84) cookie@0.6.0 workspace:@infraternal/web > @sveltejs/kit > cookie low: cookie accepts cookie name, path, and domain with out of bounds characters (<0.7.0) - https://github.com/advisories/GHSA-pxg6-pf52-xh8x 1 vulnerability (1 low) bun audit fix upgrade the vulnerable packages within their ranges bun audit fix --latest upgrade the vulnerable packages across major versions SUPPLY_CHAIN_BUN_AUDIT findings reported; this check is report-only SUPPLY_CHAIN_PASS Rust advisory/license checks complete; Bun findings are report-only PASS fast: supply-chain checks (8.531s) PASS fast: build web app (25.669s) PASS fast: cargo fmt --check (2.744s) PASS fast: cargo clippy (591.579s) PASS fast: cargo test (645.752s) PASS fast: svelte-check (39.311s) PASS fast: UI package svelte-check (12.983s) PASS fast: stream package typecheck (15.891s) PASS fast: Vitest (13.652s) PASS fast: UI package Vitest (17.312s) PASS fast: stream package Vitest (3.361s) PASS fast: OpenAPI and TypeScript client drift (121.840s) PASS fast: terminal TypeScript (6.290s) PASS fast: terminal Vitest (2.847s) ``` Worktree is clean. No issue closure requested.
Author
Owner

Clarification to the browser evidence in my previous comment: the ... marks abbreviated generated host IDs. The observed counts were Docker 7, Podman 3, SSH targets 1, with two filtered routes verified. The tree interactions and host screenshots completed before the browser flow failed its cold-JS budget assertion (119,414 bytes vs 117,760 bytes).

Clarification to the browser evidence in my previous comment: the `...` marks abbreviated generated host IDs. The observed counts were Docker 7, Podman 3, SSH targets 1, with two filtered routes verified. The tree interactions and host screenshots completed before the browser flow failed its cold-JS budget assertion (119,414 bytes vs 117,760 bytes).
Author
Owner

Finished install-timeline-ui2 on branch install-timeline-ui.

Head: e17cabef37d52cb3a894fe5aa0f02297d377e547 (merge parents: 106db0483fd9b36216477cf02c0e3161cfd1a477, 0b4fc37d555efacf9d5ca731451cfa0738ed4fb3).

The TS client generator ran against merged OpenAPI; no generated drift remained. The add-host UI, durable timeline, explicit trust, host detail link, and destructive removal plan/confirmation are committed.

INFRATERAL_VERIFY_RUN_ID=install-timeline-ui2 scripts/verify fast exited 0. Its recorded total was 497.427s. Gate output:

PASS fast: migrations are append-only (0.145s)
PASS fast: workspace package dependencies (0.394s)
PASS fast: gate target-directory and launch diagnostics tests (0.247s)
PASS fast: JavaScript dependencies (0.150s)
PASS fast: advisory review policy tests (0.132s)
PASS fast: supply-chain checks (4.445s)
PASS fast: build web app (7.554s)
PASS fast: cargo fmt --check (1.291s)
PASS fast: cargo clippy (140.888s)
PASS fast: cargo test (243.586s)
PASS fast: svelte-check (9.286s)
PASS fast: UI package svelte-check (3.705s)
PASS fast: stream package typecheck (4.079s)
PASS fast: Vitest (3.318s)
PASS fast: UI package Vitest (3.931s)
PASS fast: stream package Vitest (0.783s)
PASS fast: OpenAPI and TypeScript client drift (66.684s)
PASS fast: terminal TypeScript (4.688s)
PASS fast: terminal Vitest (2.121s)

The opt-in production browser run with the real test sshd did not complete. I stopped INFRATERAL_LIVE_HOST_INSTALL=1 INFRATERAL_ARTIFACT_DIR=/mnt/hdd/infraternal/artifacts/install-timeline-ui INFRATERAL_VERIFY_RUN_ID=install-timeline-ui2-browser scripts/verify browser at the 20-minute limit while it was still compiling the release binary; it exited 130 before Playwright results or new screenshots. The test sshd authorized_keys file was restored with sudo -n cp -a; sudo -n cmp --silent passed.

Existing timeline screenshots are present under /mnt/hdd/infraternal/artifacts/install-timeline-ui/host-install-flow/: install-timeline-{waiting-for-trust,running,failed,done}-{light,dark}-{1440x900,390x844}.png.

Leftover: complete the real-sshd browser flow (create, trust, all ten steps through inventory, removal) and refresh its screenshots from the completed run. The gate also reported the low cookie@0.6.0 Bun advisory as report-only.

Finished `install-timeline-ui2` on branch `install-timeline-ui`. Head: `e17cabef37d52cb3a894fe5aa0f02297d377e547` (merge parents: `106db0483fd9b36216477cf02c0e3161cfd1a477`, `0b4fc37d555efacf9d5ca731451cfa0738ed4fb3`). The TS client generator ran against merged OpenAPI; no generated drift remained. The add-host UI, durable timeline, explicit trust, host detail link, and destructive removal plan/confirmation are committed. `INFRATERAL_VERIFY_RUN_ID=install-timeline-ui2 scripts/verify fast` exited 0. Its recorded total was `497.427s`. Gate output: ``` PASS fast: migrations are append-only (0.145s) PASS fast: workspace package dependencies (0.394s) PASS fast: gate target-directory and launch diagnostics tests (0.247s) PASS fast: JavaScript dependencies (0.150s) PASS fast: advisory review policy tests (0.132s) PASS fast: supply-chain checks (4.445s) PASS fast: build web app (7.554s) PASS fast: cargo fmt --check (1.291s) PASS fast: cargo clippy (140.888s) PASS fast: cargo test (243.586s) PASS fast: svelte-check (9.286s) PASS fast: UI package svelte-check (3.705s) PASS fast: stream package typecheck (4.079s) PASS fast: Vitest (3.318s) PASS fast: UI package Vitest (3.931s) PASS fast: stream package Vitest (0.783s) PASS fast: OpenAPI and TypeScript client drift (66.684s) PASS fast: terminal TypeScript (4.688s) PASS fast: terminal Vitest (2.121s) ``` The opt-in production browser run with the real test sshd did not complete. I stopped `INFRATERAL_LIVE_HOST_INSTALL=1 INFRATERAL_ARTIFACT_DIR=/mnt/hdd/infraternal/artifacts/install-timeline-ui INFRATERAL_VERIFY_RUN_ID=install-timeline-ui2-browser scripts/verify browser` at the 20-minute limit while it was still compiling the release binary; it exited 130 before Playwright results or new screenshots. The test sshd `authorized_keys` file was restored with `sudo -n cp -a`; `sudo -n cmp --silent` passed. Existing timeline screenshots are present under `/mnt/hdd/infraternal/artifacts/install-timeline-ui/host-install-flow/`: `install-timeline-{waiting-for-trust,running,failed,done}-{light,dark}-{1440x900,390x844}.png`. Leftover: complete the real-sshd browser flow (create, trust, all ten steps through inventory, removal) and refresh its screenshots from the completed run. The gate also reported the low `cookie@0.6.0` Bun advisory as report-only.
Author
Owner

Starting install-ui-netauth on branch install-timeline-ui, base head e17cabef37d52cb3a894fe5aa0f02297d377e547. I’m merging dev at 7085801 as specified, then implementing the network-auth add-host and trust UI, real browser flow, and screenshot matrix. I’ll report findings and the required fast-gate output here before finishing.

Starting install-ui-netauth on branch `install-timeline-ui`, base head `e17cabef37d52cb3a894fe5aa0f02297d377e547`. I’m merging `dev` at `7085801` as specified, then implementing the network-auth add-host and trust UI, real browser flow, and screenshot matrix. I’ll report findings and the required fast-gate output here before finishing.
Author
Owner

Finding after merging dev (7085801): CreateHostInstallRequest.auth is optional and omission selects banner-based detection (crates/proto/src/install.rs), with InstallSshAuth and SshServerKind in the generated contract. The current web form request builder in packages/web/src/lib/host-install-validation.ts does not expose that choice yet. I’m implementing Detect as an omitted auth field and sending key/network only for explicit selections; the trust call will carry the selected auth value.

Finding after merging `dev` (`7085801`): `CreateHostInstallRequest.auth` is optional and omission selects banner-based detection (`crates/proto/src/install.rs`), with `InstallSshAuth` and `SshServerKind` in the generated contract. The current web form request builder in `packages/web/src/lib/host-install-validation.ts` does not expose that choice yet. I’m implementing Detect as an omitted `auth` field and sending `key`/`network` only for explicit selections; the trust call will carry the selected auth value.
Author
Owner

Decision: the NetBird-banner SSH server in crates/server/src/install_netauth_sshd.rs is a crate-private Rust test helper (NetworkSshd::start and its listener are scoped to the server test module), so the browser harness cannot launch it as a reusable target. I’m using Vitest component coverage for the NetBird trust proposal, auth override, and connect refusal message/remedy, plus the browser screenshot fixtures for those states. The real browser create/trust/inventory/remove run stays on the external OpenSSH test host in key mode.

Decision: the NetBird-banner SSH server in `crates/server/src/install_netauth_sshd.rs` is a crate-private Rust test helper (`NetworkSshd::start` and its listener are scoped to the server test module), so the browser harness cannot launch it as a reusable target. I’m using Vitest component coverage for the NetBird trust proposal, auth override, and connect refusal message/remedy, plus the browser screenshot fixtures for those states. The real browser create/trust/inventory/remove run stays on the external OpenSSH test host in key mode.
Author
Owner

Job report — browser verification remains incomplete

Branch: install-timeline-ui
Head: 257ff3fa0cd621168edde78fdb97f4426967e51a
Commits: 0ef00b8 (host install auth UI) and 257ff3f (browser coverage)

Implemented Detect automatically as the default (omitting auth), explicit key/network choices, conditional key details, detected-server context and trust-time auth override, plus the actionable network-auth refusal state. The browser fixture now covers Detect omission, proposal display, the NetBird trust/refusal states and requested screenshot naming. The loopback NetBird SSH server is crate-private test code, so NetBird UI behavior is covered by Vitest rather than a browser-backed NetBird server.

The required gate passed:

INFRATERMINAL_VERIFY_RUN_ID=install-ui-netauth scripts/verify fast
Gate: fast
Stages: 19
Elapsed  Stage
0.201s   fast: migrations are append-only
0.274s   fast: workspace package dependencies
0.277s   fast: gate target-directory and launch diagnostics tests
0.019s   fast: JavaScript dependencies
0.129s   fast: advisory review policy tests
4.898s   fast: supply-chain checks
8.673s   fast: build web app
1.539s   fast: cargo fmt --check
212.837s fast: cargo clippy
302.822s fast: cargo test
22.739s  fast: svelte-check
6.622s   fast: UI package svelte-check
8.837s   fast: stream package typecheck
6.682s   fast: Vitest
6.182s   fast: UI package Vitest
2.045s   fast: stream package Vitest
82.976s  fast: OpenAPI and TypeScript client drift
4.229s   fast: terminal TypeScript
2.288s   fast: terminal Vitest
Total: 674.269s

The known flaky suites also passed when rerun individually: packages/web/src/lib/auth.test.ts and packages/web/src/lib/stream-attachment.test.ts (both exit 0). svelte-check passed in web and UI with 0 errors and 0 warnings; node --check scripts/browser-check.mjs passed. Bun audit reported one low-severity report-only cookie@0.6.0 advisory.

The requested real OpenSSH create → trust → inventory → remove browser flow did not complete. The first browser attempt exposed an expected missing-install-job 404 that the SSH-flow console filter did not allow; that filter now matches the existing documented behavior. Three later browser attempts passed the SSH setup scenario but stopped when Playwright could not select the native auth radio. The final source now uses aria-pressed buttons, but this version was not rerun in production browser. Therefore there is no successful real host-install E2E result.

Only one screenshot was captured: /mnt/hdd/infraternal/artifacts/install-timeline-ui/netauth/form-detect-light-1440x900.png. It predates the final pressed-button selector, and the requested dark/mobile, NetBird trust-wait, running, refusal-failed and done screenshots are missing.

Every browser attempt restored /home/sshtarget/.ssh/authorized_keys and cmp passed. Temporary backups remain at /tmp/install-ui-netauth-authorized_keys.*.backup because automatic command review rejected deleting the temporary copy. The 90-minute time box was exceeded due to the cold release build and repeated full browser runs.

## Job report — browser verification remains incomplete Branch: `install-timeline-ui` Head: `257ff3fa0cd621168edde78fdb97f4426967e51a` Commits: `0ef00b8` (host install auth UI) and `257ff3f` (browser coverage) Implemented Detect automatically as the default (omitting `auth`), explicit key/network choices, conditional key details, detected-server context and trust-time auth override, plus the actionable network-auth refusal state. The browser fixture now covers Detect omission, proposal display, the NetBird trust/refusal states and requested screenshot naming. The loopback NetBird SSH server is crate-private test code, so NetBird UI behavior is covered by Vitest rather than a browser-backed NetBird server. The required gate passed: ```text INFRATERMINAL_VERIFY_RUN_ID=install-ui-netauth scripts/verify fast Gate: fast Stages: 19 Elapsed Stage 0.201s fast: migrations are append-only 0.274s fast: workspace package dependencies 0.277s fast: gate target-directory and launch diagnostics tests 0.019s fast: JavaScript dependencies 0.129s fast: advisory review policy tests 4.898s fast: supply-chain checks 8.673s fast: build web app 1.539s fast: cargo fmt --check 212.837s fast: cargo clippy 302.822s fast: cargo test 22.739s fast: svelte-check 6.622s fast: UI package svelte-check 8.837s fast: stream package typecheck 6.682s fast: Vitest 6.182s fast: UI package Vitest 2.045s fast: stream package Vitest 82.976s fast: OpenAPI and TypeScript client drift 4.229s fast: terminal TypeScript 2.288s fast: terminal Vitest Total: 674.269s ``` The known flaky suites also passed when rerun individually: `packages/web/src/lib/auth.test.ts` and `packages/web/src/lib/stream-attachment.test.ts` (both exit 0). `svelte-check` passed in web and UI with 0 errors and 0 warnings; `node --check scripts/browser-check.mjs` passed. Bun audit reported one low-severity report-only `cookie@0.6.0` advisory. The requested real OpenSSH create → trust → inventory → remove browser flow did **not** complete. The first browser attempt exposed an expected missing-install-job 404 that the SSH-flow console filter did not allow; that filter now matches the existing documented behavior. Three later browser attempts passed the SSH setup scenario but stopped when Playwright could not select the native auth radio. The final source now uses `aria-pressed` buttons, but this version was not rerun in production browser. Therefore there is no successful real host-install E2E result. Only one screenshot was captured: `/mnt/hdd/infraternal/artifacts/install-timeline-ui/netauth/form-detect-light-1440x900.png`. It predates the final pressed-button selector, and the requested dark/mobile, NetBird trust-wait, running, refusal-failed and done screenshots are missing. Every browser attempt restored `/home/sshtarget/.ssh/authorized_keys` and `cmp` passed. Temporary backups remain at `/tmp/install-ui-netauth-authorized_keys.*.backup` because automatic command review rejected deleting the temporary copy. The 90-minute time box was exceeded due to the cold release build and repeated full browser runs.
Author
Owner

Finished job install-ui-netauth on branch install-timeline-ui at head 3c96a8be7776ef094bd2e3e97ddbfee0b8646e31. No push.

The add-host form now supports Detect automatically (default; omits auth), Install key, and Network (NetBird/Tailscale SSH). The trust pause shows the detected server, proposal/current method, and fingerprint, and allows an auth override. Network-auth refusal is actionable in the failed timeline.

Focused production-browser run used the real 127.0.0.1:2222 OpenSSH test host with key mode and completed create, trust, inventory, and removal. authorized_keys was backed up with sudo -n cp -a, restored, and compared. The NetBird SSH test server helper is crate-private and not reusable by the browser harness; the NetBird trust/refusal UI states use the existing browser API fixture and Vitest coverage.

All 20 requested screenshots are in /mnt/hdd/infraternal/artifacts/install-timeline-ui/netauth/: form-detect, trust-wait-netbird, running, failed-network-refusal, and done, each at light and dark, 1440x900 and 390x844. They were copied from the successful real-browser run and byte-compared.

Focused browser gate output:

PASS browser: build release binary (332.022s)
PASS browser: install Chromium and system dependencies (4.440s)
PASS browser: terminal fixture Playwright (63.787s)
PASS browser: Playwright against release server (85.693s)
PASS browser: terminal production first-load budget (4.910s)
PASS authorized_keys restore and cmp

The unfiltered browser matrix did not pass: it stopped in the unrelated terminal-workspace check because the “Open a terminal” dialog did not appear within 5 seconds. The focused install browser run passed independently.

Final required gate output:

Gate: fast
Stages: 19
Elapsed  Stage
0.218s   fast: migrations are append-only
0.439s   fast: workspace package dependencies
0.417s   fast: gate target-directory and launch diagnostics tests
0.555s   fast: JavaScript dependencies
0.915s   fast: advisory review policy tests
5.910s   fast: supply-chain checks
10.030s  fast: build web app
1.677s   fast: cargo fmt --check
21.989s  fast: cargo clippy
227.612s fast: cargo test
28.151s  fast: svelte-check
10.731s  fast: UI package svelte-check
12.755s  fast: stream package typecheck
10.175s  fast: Vitest
9.829s   fast: UI package Vitest
2.334s   fast: stream package Vitest
21.391s  fast: OpenAPI and TypeScript client drift
5.482s   fast: terminal TypeScript
3.009s   fast: terminal Vitest
Total: 373.619s

The gate reports one low-severity cookie@0.6.0 Bun advisory as report-only. Standalone reruns of auth.test.ts and stream-attachment.test.ts also passed.

Finished job install-ui-netauth on branch `install-timeline-ui` at head `3c96a8be7776ef094bd2e3e97ddbfee0b8646e31`. No push. The add-host form now supports Detect automatically (default; omits `auth`), Install key, and Network (NetBird/Tailscale SSH). The trust pause shows the detected server, proposal/current method, and fingerprint, and allows an auth override. Network-auth refusal is actionable in the failed timeline. Focused production-browser run used the real 127.0.0.1:2222 OpenSSH test host with key mode and completed create, trust, inventory, and removal. `authorized_keys` was backed up with `sudo -n cp -a`, restored, and compared. The NetBird SSH test server helper is crate-private and not reusable by the browser harness; the NetBird trust/refusal UI states use the existing browser API fixture and Vitest coverage. All 20 requested screenshots are in `/mnt/hdd/infraternal/artifacts/install-timeline-ui/netauth/`: `form-detect`, `trust-wait-netbird`, `running`, `failed-network-refusal`, and `done`, each at `light` and `dark`, `1440x900` and `390x844`. They were copied from the successful real-browser run and byte-compared. Focused browser gate output: ``` PASS browser: build release binary (332.022s) PASS browser: install Chromium and system dependencies (4.440s) PASS browser: terminal fixture Playwright (63.787s) PASS browser: Playwright against release server (85.693s) PASS browser: terminal production first-load budget (4.910s) PASS authorized_keys restore and cmp ``` The unfiltered browser matrix did not pass: it stopped in the unrelated terminal-workspace check because the “Open a terminal” dialog did not appear within 5 seconds. The focused install browser run passed independently. Final required gate output: ``` Gate: fast Stages: 19 Elapsed Stage 0.218s fast: migrations are append-only 0.439s fast: workspace package dependencies 0.417s fast: gate target-directory and launch diagnostics tests 0.555s fast: JavaScript dependencies 0.915s fast: advisory review policy tests 5.910s fast: supply-chain checks 10.030s fast: build web app 1.677s fast: cargo fmt --check 21.989s fast: cargo clippy 227.612s fast: cargo test 28.151s fast: svelte-check 10.731s fast: UI package svelte-check 12.755s fast: stream package typecheck 10.175s fast: Vitest 9.829s fast: UI package Vitest 2.334s fast: stream package Vitest 21.391s fast: OpenAPI and TypeScript client drift 5.482s fast: terminal TypeScript 3.009s fast: terminal Vitest Total: 373.619s ``` The gate reports one low-severity `cookie@0.6.0` Bun advisory as report-only. Standalone reruns of `auth.test.ts` and `stream-attachment.test.ts` also passed.
Author
Owner

Starting Job install-ui-merge (#46). Branch: install-timeline-ui. Base head: 3c96a8be77. Integrating dev at 056ef45435; will resolve scripts/browser-check.mjs, compare the terminal dialog check on dev and merged tree, then run the requested verification gates.

Starting Job install-ui-merge (#46). Branch: install-timeline-ui. Base head: 3c96a8be7776ef094bd2e3e97ddbfee0b8646e31. Integrating dev at 056ef454356fde7488a207bc1ad735c1b04e6b81; will resolve scripts/browser-check.mjs, compare the terminal dialog check on dev and merged tree, then run the requested verification gates.
Author
Owner

Finding/decision: the branch’s live OpenSSH install flow was the remaining browser check that appended the server install key to the shared /home/sshtarget/.ssh/authorized_keys and targeted port 2222. The merged flow now starts the existing per-test sshd helper with a unique authorized_keys file and ephemeral port, validates the install-only restricted Ed25519 line, and allows requested remote commands for the multi-command install protocol (docs/contracts.md §8). The UI fixture still covers NetBird states; dev’s independent tree, DataTable, perf-selector, and isolated SSH checks are retained.

Finding/decision: the branch’s live OpenSSH install flow was the remaining browser check that appended the server install key to the shared /home/sshtarget/.ssh/authorized_keys and targeted port 2222. The merged flow now starts the existing per-test sshd helper with a unique authorized_keys file and ephemeral port, validates the install-only restricted Ed25519 line, and allows requested remote commands for the multi-command install protocol (docs/contracts.md §8). The UI fixture still covers NetBird states; dev’s independent tree, DataTable, perf-selector, and isolated SSH checks are retained.
Author
Owner

Verification finding: a direct scripts/build-web attempt in the dev worktree failed because its existing JavaScript install could not resolve motion/mini from packages/ui/src/motion.ts. I am switching to scripts/verify browser, whose prepare step refreshes dependencies from that tree’s bun.lock before rebuilding; this is an environment/dependency freshness failure, not a Svelte or Vitest failure.

Verification finding: a direct scripts/build-web attempt in the dev worktree failed because its existing JavaScript install could not resolve motion/mini from packages/ui/src/motion.ts. I am switching to scripts/verify browser, whose prepare step refreshes dependencies from that tree’s bun.lock before rebuilding; this is an environment/dependency freshness failure, not a Svelte or Vitest failure.
Author
Owner

Dev baseline browser gate started on commit 056ef45435. Its real output began with: WARN load5=17.05 exceeds online CPU count=8; timing-sensitive checks may be delayed. This VM is under heavy concurrent load, so I will record the terminal-dialog result with that condition and compare it to the merged run.

Dev baseline browser gate started on commit 056ef454356fde7488a207bc1ad735c1b04e6b81. Its real output began with: WARN load5=17.05 exceeds online CPU count=8; timing-sensitive checks may be delayed. This VM is under heavy concurrent load, so I will record the terminal-dialog result with that condition and compare it to the merged run.
Author
Owner

The dev gate’s Rust step failed because RUSTC_WRAPPER=sccache resolved no executable on this gate’s PATH; /home/kayg/.local/bin/sccache 0.18.0 is present. I will use its absolute path for the next run. The gate had already refreshed JS dependencies and passed its web bundle step.

The dev gate’s Rust step failed because RUSTC_WRAPPER=sccache resolved no executable on this gate’s PATH; /home/kayg/.local/bin/sccache 0.18.0 is present. I will use its absolute path for the next run. The gate had already refreshed JS dependencies and passed its web bundle step.
Author
Owner

Dev baseline result: scripts/verify browser on 056ef454 built the release binary successfully, then failed at before reaching checkTerminalWorkspace. Exact finding: . Therefore this run did not execute the terminal dialog check; the check implementation itself has no diff between dev and the branch. Dev browser log: /mnt/hdd/infraternal/artifacts/verify/install-ui-merge-dev2/step-4.log.

Dev baseline result: scripts/verify browser on 056ef454 built the release binary successfully, then failed at before reaching checkTerminalWorkspace. Exact finding: . Therefore this run did not execute the terminal dialog check; the check implementation itself has no diff between dev and the branch. Dev browser log: /mnt/hdd/infraternal/artifacts/verify/install-ui-merge-dev2/step-4.log.
Author
Owner

Dev baseline result: scripts/verify browser on 056ef454 built the release binary successfully, then failed at container-detail cold JavaScript before reaching checkTerminalWorkspace. Exact finding: container-detail cold JavaScript must stay at least 5 KiB under the 120 KiB cap (maximum 117,760 bytes): 119406 bytes. Therefore this run did not execute the terminal dialog check; the check implementation itself has no diff between dev and the branch. Dev browser log: /mnt/hdd/infraternal/artifacts/verify/install-ui-merge-dev2/step-4.log.

Dev baseline result: scripts/verify browser on 056ef454 built the release binary successfully, then failed at container-detail cold JavaScript before reaching checkTerminalWorkspace. Exact finding: container-detail cold JavaScript must stay at least 5 KiB under the 120 KiB cap (maximum 117,760 bytes): 119406 bytes. Therefore this run did not execute the terminal dialog check; the check implementation itself has no diff between dev and the branch. Dev browser log: /mnt/hdd/infraternal/artifacts/verify/install-ui-merge-dev2/step-4.log.
Author
Owner

Finding/decision for #46:

  • The live install did not reach done within 180 seconds with the isolated per-test sshd fixture. I moved only that real install flow to the provisioned sshtarget service on 127.0.0.1:2222. The browser check now saves /home/sshtarget/.ssh/authorized_keys with sudo cp -a, appends the validated restricted install key, and restores with cp -a plus cmp in a finally block. The full browser run reported: PASS browser host install: create, trust, inventory, removal plan, removal, and reload recovery.

  • The dev browser run stopped before terminal-workspace at the cold container-detail JS budget: container-detail cold JavaScript must stay at least 5 KiB under the 120 KiB cap (maximum 117,760 bytes): 119406 bytes. The merged run reached the terminal-workspace check and captured its dialog/workspace screenshots. The check implementation has no diff from dev. The later merged browser failure was at the responsive route check on GET /api/v1/containers returning 503.

Screenshots from the merged run:

  • /mnt/hdd/infraternal/artifacts/verify/install-ui-merge/browser/light-1440x900-terminals-dialog.png
  • /mnt/hdd/infraternal/artifacts/verify/install-ui-merge/browser/light-390x844-terminals-dialog.png
  • /mnt/hdd/infraternal/artifacts/verify/install-ui-merge/browser/light-1440x900-terminals-workspace.png
  • /mnt/hdd/infraternal/artifacts/verify/install-ui-merge/browser/light-390x844-terminals-workspace.png
Finding/decision for #46: - The live install did not reach `done` within 180 seconds with the isolated per-test sshd fixture. I moved only that real install flow to the provisioned `sshtarget` service on 127.0.0.1:2222. The browser check now saves `/home/sshtarget/.ssh/authorized_keys` with `sudo cp -a`, appends the validated restricted install key, and restores with `cp -a` plus `cmp` in a `finally` block. The full browser run reported: `PASS browser host install: create, trust, inventory, removal plan, removal, and reload recovery`. - The dev browser run stopped before terminal-workspace at the cold container-detail JS budget: `container-detail cold JavaScript must stay at least 5 KiB under the 120 KiB cap (maximum 117,760 bytes): 119406 bytes`. The merged run reached the terminal-workspace check and captured its dialog/workspace screenshots. The check implementation has no diff from dev. The later merged browser failure was at the responsive route check on `GET /api/v1/containers` returning 503. Screenshots from the merged run: - `/mnt/hdd/infraternal/artifacts/verify/install-ui-merge/browser/light-1440x900-terminals-dialog.png` - `/mnt/hdd/infraternal/artifacts/verify/install-ui-merge/browser/light-390x844-terminals-dialog.png` - `/mnt/hdd/infraternal/artifacts/verify/install-ui-merge/browser/light-1440x900-terminals-workspace.png` - `/mnt/hdd/infraternal/artifacts/verify/install-ui-merge/browser/light-390x844-terminals-workspace.png`
Author
Owner

Finished #46. Branch install-timeline-ui head: 1a1cfd64cc4df2bc39b70549d364ba22e212bf5d.

The merge commit resolved the sole scripts/browser-check.mjs conflict by retaining both artifact directories and their mkdir calls; dev's isolated sshd fixtures, load-tolerant DataTable check, perf selector updates and sidebar tree checks are present. Follow-up commit 1a1cfd6 uses the provisioned sshtarget account for the live installer because the isolated fixture did not complete within 180 seconds, and restores its authorized_keys file with cp -a and cmp.

INFRATERNAL_VERIFY_RUN_ID=install-ui-merge scripts/verify fast exited 0. Gate output:

PASS fast: migrations are append-only (0.208s)
PASS fast: workspace package dependencies (4.003s)
PASS fast: gate target-directory and launch diagnostics tests (0.495s)
PASS fast: JavaScript dependencies (0.087s)
PASS fast: advisory review policy tests (0.199s)
PASS fast: supply-chain checks (21.241s)
PASS fast: build web app (10.396s)
PASS fast: cargo fmt --check (1.320s)
PASS fast: cargo clippy (276.511s)
PASS fast: cargo test (227.222s)
PASS fast: svelte-check (12.158s)
PASS fast: UI package svelte-check (4.365s)
PASS fast: stream package typecheck (4.884s)
PASS fast: Vitest (3.819s)
PASS fast: UI package Vitest (4.778s)
PASS fast: stream package Vitest (1.096s)
PASS fast: OpenAPI and TypeScript client drift (51.462s)
PASS fast: terminal TypeScript (2.167s)
PASS fast: terminal Vitest (1.165s)

The full production browser run built the release binary and passed the terminal fixture check. The live install path completed; exact output:

PASS browser host install: create, trust, inventory, removal plan, removal, and reload recovery

The full browser gate later failed at the responsive route check. Exact gate output:

FAIL browser: Playwright against release server (329.481s)
error: light/desktop: browser errors: {"pageErrors":[],"consoleErrors":["Failed to load resource: the server responded with a status of 503 (Service Unavailable) (/api/v1/containers)"],"unauthorizedResponses":[]}

Terminal finding: dev's browser run stopped before terminal-workspace at the cold container-detail JS budget (119406 bytes vs the 117,760-byte maximum). The terminal helper is unchanged between dev and this branch; the merged browser run captured the terminal dialog and workspace screenshots at desktop and 390×844. This does not establish whether dev would hit the same 5-second dialog timeout because its run stopped earlier.

Finished #46. Branch `install-timeline-ui` head: `1a1cfd64cc4df2bc39b70549d364ba22e212bf5d`. The merge commit resolved the sole `scripts/browser-check.mjs` conflict by retaining both artifact directories and their mkdir calls; dev's isolated sshd fixtures, load-tolerant DataTable check, perf selector updates and sidebar tree checks are present. Follow-up commit `1a1cfd6` uses the provisioned `sshtarget` account for the live installer because the isolated fixture did not complete within 180 seconds, and restores its authorized_keys file with `cp -a` and `cmp`. `INFRATERNAL_VERIFY_RUN_ID=install-ui-merge scripts/verify fast` exited 0. Gate output: ```text PASS fast: migrations are append-only (0.208s) PASS fast: workspace package dependencies (4.003s) PASS fast: gate target-directory and launch diagnostics tests (0.495s) PASS fast: JavaScript dependencies (0.087s) PASS fast: advisory review policy tests (0.199s) PASS fast: supply-chain checks (21.241s) PASS fast: build web app (10.396s) PASS fast: cargo fmt --check (1.320s) PASS fast: cargo clippy (276.511s) PASS fast: cargo test (227.222s) PASS fast: svelte-check (12.158s) PASS fast: UI package svelte-check (4.365s) PASS fast: stream package typecheck (4.884s) PASS fast: Vitest (3.819s) PASS fast: UI package Vitest (4.778s) PASS fast: stream package Vitest (1.096s) PASS fast: OpenAPI and TypeScript client drift (51.462s) PASS fast: terminal TypeScript (2.167s) PASS fast: terminal Vitest (1.165s) ``` The full production browser run built the release binary and passed the terminal fixture check. The live install path completed; exact output: ```text PASS browser host install: create, trust, inventory, removal plan, removal, and reload recovery ``` The full browser gate later failed at the responsive route check. Exact gate output: ```text FAIL browser: Playwright against release server (329.481s) error: light/desktop: browser errors: {"pageErrors":[],"consoleErrors":["Failed to load resource: the server responded with a status of 503 (Service Unavailable) (/api/v1/containers)"],"unauthorizedResponses":[]} ``` Terminal finding: dev's browser run stopped before terminal-workspace at the cold container-detail JS budget (`119406` bytes vs the 117,760-byte maximum). The terminal helper is unchanged between dev and this branch; the merged browser run captured the terminal dialog and workspace screenshots at desktop and 390×844. This does not establish whether dev would hit the same 5-second dialog timeout because its run stopped earlier.
Author
Owner

Starting host lifecycle status and general host removal work on branch host-status-remove, based on dev 173525d835. Scope: typed server-derived host lifecycle status across API/client/UI, and audited plan-based DELETE host removal with CLI/MCP parity, tests, and browser verification for SSH-only removal.

Starting host lifecycle status and general host removal work on branch host-status-remove, based on dev 173525d8358a2576e681576605a7a7c5f1b9ebdd. Scope: typed server-derived host lifecycle status across API/client/UI, and audited plan-based DELETE host removal with CLI/MCP parity, tests, and browser verification for SSH-only removal.
Author
Owner

The first full production-browser run failed at browser: Playwright against release server after 523.554s. The log-flood check reported lineRate=18391.313981708816, fps=59.82716596459495, retained=10000, bytes=210000, dropped=23200, renderedRows=20; only the average-FPS floor was exceeded. The current harness samples requestAnimationFrame over 1.8s and rejects any average below 60. I’m collecting frame-interval p99/max evidence on the next strict run while keeping that assertion in place; the 320px diagnostic is also being represented by a long host-name fixture.

The first full production-browser run failed at `browser: Playwright against release server` after 523.554s. The log-flood check reported `lineRate=18391.313981708816`, `fps=59.82716596459495`, `retained=10000`, `bytes=210000`, `dropped=23200`, `renderedRows=20`; only the average-FPS floor was exceeded. The current harness samples `requestAnimationFrame` over 1.8s and rejects any average below 60. I’m collecting frame-interval p99/max evidence on the next strict run while keeping that assertion in place; the 320px diagnostic is also being represented by a long host-name fixture.
Author
Owner

Finding: the generated hosts API currently exposes only HostStatus::{online,offline} (crates/proto/src/resources.rs), while packages/web/src/lib/shell/infrastructure-tree.ts derives setting-up from engine and SSH-discovery state. SSH trust is stored in each owning infraternal agent's HostKeyStore (crates/agent/src/lib.rs / crates/ssh/src/host_keys.rs), so SSH-only removal needs an owner-routed signed forget operation before deleting server-side host settings. The list path will keep lifecycle enrichment batched to avoid per-host storage lookups.

Finding: the generated hosts API currently exposes only `HostStatus::{online,offline}` (`crates/proto/src/resources.rs`), while `packages/web/src/lib/shell/infrastructure-tree.ts` derives `setting-up` from engine and SSH-discovery state. SSH trust is stored in each owning infraternal agent's `HostKeyStore` (`crates/agent/src/lib.rs` / `crates/ssh/src/host_keys.rs`), so SSH-only removal needs an owner-routed signed forget operation before deleting server-side host settings. The list path will keep lifecycle enrichment batched to avoid per-host storage lookups.
Author
Owner

Browser run 2 on browser-green (head 3937900) passed every route check, the long-host-label 320px wrapping check, and all cold-JS budgets. The only failure was the final log-flood frame-rate assertion: average 59.9967 FPS, p99 frame interval 16.8 ms, max 33.4 ms, and zero intervals over 50 ms. The whole verify command had been run under nice -n 10, including Playwright/Chromium. I am rerunning scripts/verify browser at normal priority to distinguish scheduler noise from a product regression; the strict UI and cold-JS assertions remain unchanged.

Browser run 2 on `browser-green` (head `3937900`) passed every route check, the long-host-label 320px wrapping check, and all cold-JS budgets. The only failure was the final log-flood frame-rate assertion: average 59.9967 FPS, p99 frame interval 16.8 ms, max 33.4 ms, and zero intervals over 50 ms. The whole verify command had been run under `nice -n 10`, including Playwright/Chromium. I am rerunning `scripts/verify browser` at normal priority to distinguish scheduler noise from a product regression; the strict UI and cold-JS assertions remain unchanged.
Author
Owner

Normal-priority full browser run at 3937900 reproduced the only failure, so low process priority was not the root cause. checkFloodRetention reported 53.47299 FPS, p99/max frame interval 66.6 ms, 2 intervals over 50 ms; retained lines=10,000, rendered DOM rows=20, bytes=210,000, line rate=18,081.6/s. The long 320px host filter label wrapped without clipping, and all route cold-JS budgets passed. The remaining failure is isolated to the browser log flood performance measurement; investigating the client rendering/update path.

Normal-priority full browser run at `3937900` reproduced the only failure, so low process priority was not the root cause. `checkFloodRetention` reported 53.47299 FPS, p99/max frame interval 66.6 ms, 2 intervals over 50 ms; retained lines=10,000, rendered DOM rows=20, bytes=210,000, line rate=18,081.6/s. The long 320px host filter label wrapped without clipping, and all route cold-JS budgets passed. The remaining failure is isolated to the browser log flood performance measurement; investigating the client rendering/update path.
Author
Owner

Lifecycle status is now a typed HostLifecycleStatus on host list and detail responses. The server combines install state, identity/tunnel state, SSH owner availability, and local engine availability. The storage test lifecycle_sources_load_500_hosts_without_per_host_storage_reads passes with exactly three batched source scans for 500 hosts. The sidebar tree, Hosts list, dashboard, and detail display the API status directly.

Lifecycle status is now a typed `HostLifecycleStatus` on host list and detail responses. The server combines install state, identity/tunnel state, SSH owner availability, and local engine availability. The storage test `lifecycle_sources_load_500_hosts_without_per_host_storage_reads` passes with exactly three batched source scans for 500 hosts. The sidebar tree, Hosts list, dashboard, and detail display the API status directly.
Author
Owner

Starting job one-add-host (#46).
Branch: one-add-host
Base head: 851d502909
Scope: unify all add-host entry points into the install-first / SSH-target flow, add state and browser coverage, capture required screenshots, and run scripts/verify fast.

Starting job one-add-host (#46). Branch: one-add-host Base head: 851d50290998f1328b7e5557f9084a5d7d0dff07 Scope: unify all add-host entry points into the install-first / SSH-target flow, add state and browser coverage, capture required screenshots, and run scripts/verify fast.
Author
Owner

Starting install-single-source: branch install-single-source, base/head 851d50290998f1328b7e5557f9084a5d7d0dff07, only writer. Scope: host-owned current SSH settings for install execution/retry, endpoint-bound host-key trust, and setup-first host detail states. Will run the requested fast gate and real-sshd browser recovery check; will not push or run merge.

Starting install-single-source: branch `install-single-source`, base/head `851d50290998f1328b7e5557f9084a5d7d0dff07`, only writer. Scope: host-owned current SSH settings for install execution/retry, endpoint-bound host-key trust, and setup-first host detail states. Will run the requested fast gate and real-sshd browser recovery check; will not push or run merge.
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/infraternal-v0#46
No description provided.