Preserve browser chat history through interrupted migrations
Reviewed backend fixture corrections — November 7
Current head: 15b91680e0515f955d4a17d0b859d2e4d31bc800. The advisory auth shard exposed six storage-resolver failures before reaching its existing 55-minute deadline. Reproducing an original case confirmed that synthetic org/team membership setup omitted the now-required trusted write context. Both setup calls now supply TrustedMembershipWriteContext(BOOTSTRAP); existing assertions and production code are unchanged.
Two further inherited faults were reproduced on this branch: 36 accounting setup errors when CI disables plugin autoload, and a stale generated-inventory assertion. The accounting module now explicitly registers the already-declared pytest-mock plugin. Existing test doubles/helper returns have typing casts for the changed-file mypy gate. The existing generator refreshed only three source-line references in each inventory artifact. These four shared files match the independently reviewed #3429 versions byte-for-byte.
Validation: all 79 VN idempotency/repository tests pass with SQLite and isolated PostgreSQL 18, including all 12 targeted cold/warm resolver cases. All 73 accounting/inventory cases pass with CI plugin autoload disabled; all 63 accounting cases also pass with normal autoload. Exact mypy 2.4.1 and Ruff pass both changed Python files. Bandit findings match baseline (18 resolver and 49 accounting low-severity B101 test assertions, zero scan errors). Independent review found no actionable issue. The temporary PostgreSQL test container was removed.
Limits: the full hosted auth shard was not rerun locally. Its earlier deadline and abort/native diagnostics are not proven to be caused or fixed by these fixture corrections; fresh current-head CI must verify the result. No product behavior, dependency, workflow, assertion, retry, or timeout changed. Earlier history/onboarding/presentation validation and its limits remain below. The requester’s Change summary waiver remains valid. No merge or auto-merge is authorized.
Earlier presentation CI correction — November 7
Previous head: b9338eed0b37dd98000f4ee0f8cc4c07746e1c04. The presentation coverage test now waits for the same storage assertion before reloading: displaying the second edit happens before asynchronous digest validation persists it. Every assertion and timeout remains unchanged, including post-reload recovery checks. No product code changes.
A controlled 50 ms digest delay reproduced the exact original storage failure and passes after the correction. All 111 workspace tests pass, along with full WebUI TypeScript using the standard 8192 MiB setting, scoped ESLint and independent review. The temporary reproduction copy and task-created dependency link were removed. Bandit does not apply to this TypeScript test-only correction.
Fresh required and advisory CI on this head is awaiting verification. Earlier CI reports below describe superseded heads. The requester's Change summary waiver remains in force. No merge or auto-merge has been requested.
Summary
Legacy browser migration copied messages individually, cleared the source even when a message write failed, and could still set the completion flag. This change copies each conversation in one IndexedDB transaction. A retry fills missing records and preserves destination edits and ownership. Conflicts with claimed conversations stop the migration, including attempts to attach unseen session files. Local checks run offline, and browser storage errors propagate to a retry on reload.
The legacy source remains on-device after a successful copy as well as after a failure. The existing completion flag prevents the normal startup path from replaying it. This change cannot reconstruct data removed by an earlier version. The existing prompt migration continues to preserve unclaimed legacy records.
Verification
- 38 tests passed covering interrupted copies, offline startup, concurrent retries, claimed conversations, cross-history messages, session-file conflicts, storage read errors and existing prompt ownership.
- A headless Chromium smoke used synthetic legacy storage with the real Dexie implementation and IndexedDB. An injected write failure rolled back the history transaction. Concurrent retries preserved edited records.
- WebUI typecheck passed. Touched-file ESLint reported zero errors and 10 warnings.
- The current public extension built successfully. Both affected NE-03/NE-06 extension browser cases passed with all existing assertions against an isolated local backend and synthetic data; four focused timer checks reproduced the inherited onboarding race on both the exact base and current code.
- Full WebUI build and real user profiles were not exercised. The standard browser runner could not start Next through the existing external dependency symlink; the extension cases were run directly through the existing Playwright config. An initial outline run lost its backend during runner cleanup; its isolated rerun passed. Bandit applies to Python code; this change is TypeScript only.
Task: TASK-15428. ADR required: no. The changes preserve the existing storage schema and the destination ownership contract.
CI follow-up
CI follow-up completes the synthetic Chrome storage fixture with storage.sync.get, which the shared UI configuration uses for nickname reads. Failure assertions now identify the intended rollback/ownership/storage error and retain normal-entry rejection coverage. Both committed test configurations pass all 38 focused tests. The focused V8 coverage run passes all six retry cases, and WebUI typecheck and touched-file lint pass. Independent review found no remaining issue. At 11:07 UTC on November 7, all eight protected checks for head 92e77a72 report SUCCESS; advisory checks are still pending and the coverage limitation below remains.
The notes/chat UX job also exposed an inherited onboarding race: selecting a note changes the query string and can dismiss the two-second tutorial prompt before the test reaches it. The failing head and exact base have identical prompt/test sources, and a focused base/head reproduction confirms the race. The two affected extension tests now wait for and dismiss the prompt before opening the note. All prompt and editor assertions remain; there are no added retries, skips or timeout changes. Independent review passed, as did both affected extension cases, focused lint and the repository's standard 8 GB WebUI typecheck. The current head now has all eight protected checks successful as of the timestamp above.
Advisory coverage limitation (November 7)
The current-head shared UI coverage shard 14/16 reports 2,311 passed and one failure in StandaloneHtmlWorkspace.test.tsx: the same-key draft cleanup test expected the second edit in session storage but observed the earlier edit. The complete PresentationStudio source/test tree, principal-scope hook, shared services, Vitest configuration/setup, package manifests, lockfile and workflow are byte-identical to the run's exact base 2f402bd7.
Source inspection shows that the editor displays a candidate before asynchronous validation calls the persistence handler; this test waits for that displayed value and then immediately inspects session storage. That is consistent with a pre-existing wait race, but the CI-specific timing has not been reproduced. The corresponding coverage job in baseline run 42300851297 was skipped, so it supplies no passing or failing baseline evidence. This failure is not proven inherited; no history-migration regression is demonstrated. No unrelated presentation change, assertion relaxation or CI retry was made. Coverage is report-only and is not a dependency of frontend-required; that required gate subsequently passed, and all eight protected checks report SUCCESS at 11:07 UTC.
Requester Change summary exception
The requester explicitly waived the human-written Change summary requirement for PRs #3428, #3429, #3430 and #3431 in the CI follow-up chat, answering “waived” on November 6, 2026 (Pacific). Required checks and review still apply.
Summary by cubic
Legacy browser migration now copies each conversation in a single IndexedDB transaction and keeps the legacy source on-device after success or failure, so interrupted migrations no longer lose chat history.
- Retries fill missing records while preserving destination edits and ownership; conflicts with claimed conversations stop the migration.
- Local migration checks run offline, and browser storage errors propagate to a retry on reload.
- Reopening Prompt Assist now clears pending focus callbacks so a delayed drawer close can't return focus to the textarea and close the menu.
- Test-only CI fixes wait for async behavior before asserting: notes tutorial dismissal, persisted draft, Companion layout, verified history account, download and asset refresh retry readiness, log queue drain, watchlist search selection, and visual review controls.
- Ten PR-triggered browser jobs are pinned to Ubuntu 24.04 because Playwright 1.58 rejects the floating
ubuntu-latestimage; three unrelated anonymous Bun setup failures remain unexplained.
Advisory shared-UI readiness follow-up (November 7)
Two coverage shards exposed test setup races: Companion setup notice and accepted LocalChatList selection. The Companion notice mounts before the saved layout supplies all required card names; its existing text assertion now waits for that state. The current-account selection test now waits for the existing selection probe to confirm account verification before clicking, so verification cannot replace the reader during the held-read scenario. Both changes are test-only. All original selection, failed/unmounted, prior-chat, heading-absence and single-notice assertions remain; no timeouts, retries, product behavior or ownership protections change.
Controlled delayed-layout and account-verification reproductions failed before the changes and passed afterward (all five controlled parameter cases). Both complete test files pass all 45 cases with V8 coverage; full WebUI TypeScript at the standard 8192 MiB setting, scoped ESLint, task-format and diff checks pass. Independent review found no actionable issue and inspected the connected components, ownership checks and controlled evidence. Bandit is inapplicable to these TypeScript test-only changes. The temporary shared-UI dependency link was removed; existing dependencies were preserved.
The full hosted coverage shards and browser E2E were not rerun locally. Fresh current-head CI remains required. Prior history-migration, onboarding and presentation evidence and limitations, plus the requester’s Change summary waiver, remain in force. No merge or auto-merge is requested.
Advisory download refresh test follow-up (November 8)
The shared UI coverage shard 3/16 failure expected a third download-list request but observed two. The stale-error test now waits for the real AntD Refresh downloads button to leave its loading state before its existing single retry click. Error visibility alone can precede click readiness. The original request-count and error-clearing assertions, product behavior, timeouts and retries remain unchanged.
A controlled scheduling probe reproduced the exact expected-three/observed-two assertion before the correction and passed afterward, with the real button still showing its loading class when the error appeared. This probe delays the rejected API mock by 50 ms and overrides RTL's async wrapper after the first click, including its act-environment handling; it is not a byte-identical CI environment. All 32 cases in the affected file pass with V8 coverage (135.40 seconds). Full WebUI TypeScript on Node 20.20.2 at 8192 MiB with incremental compilation disabled passes. Scoped ESLint has zero errors and the same four pre-existing warnings as the original file. Independent review found no actionable issue after inspecting connected product, panel, AntD code and reproduction evidence; the reviewer did not rerun tests.
Only the temporary shared-UI dependency link created for this repair was removed; pre-existing dependencies and memory files remain. Bandit is inapplicable to the TypeScript test/task-only correction. The full hosted coverage shard and browser E2E were not rerun locally, and fresh CI on commit 06c4f7e61f remains required. Earlier evidence, test limits and the requester Change summary waiver remain valid. No merge, auto-merge or base update is requested.
Logging test reload follow-up (November 8)
The current-head core-server-smoke shard exposed a test isolation race: a queued log writer could finish loading settings after the test helper reloaded the module and overwrite its new state. The runtime-timeout test observed about five seconds against its unchanged sub-half-second assertion. The helper now drains the existing queue before reload, using the same reviewed correction already on PR #3430. An Event-controlled regression detects the pending settings read changing an already-held lock path; it demonstrates the race, without claiming to recreate the exact CI timing. The existing secret-extra dictionary also receives the annotation required by mypy. Product code, original assertions, timeouts, retries, dependencies and workflows are unchanged.
Validation: the regression fails before the queue drain; all 22 affected-file tests pass afterward, including the original timeout case. The inspected Logging subset passes 54 tests, excluding the Jobs-storage trace-context suite. Exact mypy 2.4.1 and Ruff 0.17.4 pass. Bandit 1.8.6 adds only the new test assertion (56 to 57 B101 findings); its existing synthetic-secret B105 finding is unchanged, with no scan errors. Canonical task and diff checks pass. Independent review found no actionable issue and independently passed the reuse-then-regression ordering pair (2 tests); the reviewer inspected the broader validation evidence rather than rerunning those suites.
The full smoke shard was not rerun locally because it includes database fixtures. Logging teardown initialized isolated synthetic SQLite storage; no restore, recovery or Docker command ran. Fresh hosted checks on this new head are still required. Earlier test limits and the requester’s Change summary waiver remain in force. No merge or base update.
Browser runner compatibility
ubuntu-latest selected Ubuntu 26.04.1 for the UX Smoke and WebUI Research Workspace Parity jobs. The existing Playwright 1.58.0 cannot install Chromium for that platform, so both jobs failed before browser tests. The ten PR-triggered browser jobs now select Ubuntu 24.04. Their commands, dependencies, assertions, timeouts, retries, admission conditions and protected check names are unchanged.
Validation: 60 existing required-workflow contracts and 17 frontend/research contracts pass. Parsed YAML comparison verifies that only the ten runner values changed. The integrity-verified Playwright 1.58.0 package exposes Chromium download URLs and native dependencies for Ubuntu 24.04, and none for Ubuntu 26.04. This platform-selection probe does not replace hosted Linux/browser execution. Scoped task normalization and diff checks pass; Bandit does not apply to these YAML/task-only edits. ADR required: no; this restores compatibility with the existing toolchain. Scheduled-only workflows were not changed.
The separate Bun installation failures still lack a package name or established cause and occurred on both Ubuntu 24.04 and 26.04; this runner pin is not claimed to fix them. Fresh CI on the updated head is required. Earlier test limits and the requester’s Change summary waiver remain in force. No merge or base update is authorized.
Independent review found no actionable issue after checking all workflow consumers, parsed scope, package integrity and platform probe. Hosted CI remains required.
Watchlist search readiness follow-up (TASK-15428)
The shared-UI coverage shard observed a search request before its results rendered, then failed to find the Item Two row. The test now awaits that same accessible row before its single click, porting the reviewed fix from public PR #3430. Debounce counts, reader selection and the zero-extra-fetch assertion remain unchanged; product code, timeouts, retries and dependencies are untouched.
Validation: a controlled 50 ms delay in only the mocked search response reproduces the exact missing-row failure before correction and passes afterward. All three affected-file tests pass with V8 coverage (18.15 seconds). Full WebUI TypeScript and scoped ESLint pass on Node 20.19.5. Initial local lint-base and workspace-package setup errors were corrected and retained separately. Task normalization and diff checks pass. Independent connected-code and diagnostic review found no actionable issue; the reviewer did not rerun the suites. Bandit is inapplicable to this TypeScript test/task-only change; no ADR is required.
The full hosted coverage shard and browser E2E were not rerun locally. Fresh CI is required on this new head; prior-head successes do not transfer. No local backend, database or recovery work ran. Temporary dependency links were removed while preserving their targets and :memory:.ses. Earlier test limits and the requester's Change summary waiver remain in force. No merge or base update is authorized.
Prompt Assist focus follow-up (TASK-15428)
Opening Prompt Assist now retires a previous drawer's pending focus return. A delayed close callback could otherwise focus the textarea and dismiss the reopened menu. The handler uses a stable callback because the menu reports visibility through a layout effect. A controlled regression reproduces the focus steal before the correction and verifies retained menu focus plus a usable Review action afterward.
Validation: 85 component/menu tests with V8 coverage; all 22 mock-backed packaged-extension browser cases in headed Chromium with retries disabled and zero skipped/unexpected/flaky results; production Chrome build; full WebUI TypeScript and extension compile; scoped ESLint with no warnings; task-format/diff checks. Independent connected-code review found no actionable issue in the final correction. The reviewer inspected evidence rather than rerunning the runtime suites. Bandit does not apply to this TypeScript product/test and task-only scope.
The original CI timeout in job 128768825029 was not reproduced exactly: six isolated baseline browser runs and two scheduling probes passed. This fixes a demonstrated delayed-close ownership bug; fresh hosted CI must verify the original failing job. Broader local browser validation caught an update loop in the first inline-handler implementation; that intermediate version was corrected before publication, and the final stable callback passed all 22 selected cases. The configured real-backend smoke case and full hosted job were not run locally. Existing browser assertions, timeouts, retries, dependencies and workflows remain unchanged. No backend, database, Docker, restore/recovery operation, CI rerun, merge or base update was performed. Prior waivers and test limits remain in force.
Visual review test readiness follow-up (TASK-15428)
The shared-UI coverage shard 9/16 reached the accepted status while AntD still blocked the Reject button, so the existing single click produced only one of the expected two review requests. The test now waits for that same button to leave its loading state before clicking. This ports the reviewed public #3430 correction; the complete test file matches that reference. Product behavior, original clicks and assertions, timeouts, retries, dependencies and workflows are unchanged.
Validation: delaying only the mocked review response by 50 ms reproduces the exact expected-two/received-one assertion before the correction and passes afterward. This is a controlled scheduling reproduction, not an identical hosted environment. All 66 affected-file tests pass with V8 coverage (24.84 seconds, zero skips). Full WebUI TypeScript passes on Node 20.19.5 with 8192 MiB and incremental compilation disabled. Scoped ESLint reports zero errors and the same 50 baseline warnings. Task normalization and diff checks pass. Independent connected-code, AntD loading-guard and evidence review found no actionable issue; the reviewer did not rerun runtime suites. Bandit is inapplicable to this TypeScript test/task-only change; no ADR is required.
The five temporary dependency links and two empty directories were removed; dependency targets and :memory:.ses were preserved. Full hosted coverage shard and browser E2E were not run locally. Fresh CI on fb467fe76693a44214bee6103a38e8d6838562c3 is required; prior-head successes do not transfer, and the old job 128792483806 is superseded. No backend, database, Docker, restore/recovery operation or CI rerun occurred for this repair. Earlier test limits and the requester’s Change summary waiver remain valid. No merge or base update is authorized.
Asset refresh retry readiness follow-up
The preceding head's frontend unit shard installed all 3584 packages, then the asset-refresh retry test expected two requests but observed one; 50 other tests passed. Error text can appear before the real AntD Refresh downloads button releases its loading click guard. The test now waits for that guard to clear before its existing single retry click. The original request-count/error-clearing assertions, product code, timeouts, retries and dependencies are unchanged.
The original target passed locally. A controlled 50ms mocked rejection plus RTL asyncWrapper override after the first click observed the real loading state and reproduced the exact expected-two/observed-one failure before the correction; the same probe passed afterward. This override also changes act handling and is not an exact CI recreation. All 32 affected-file tests passed with V8 coverage in 43.03s; full WebUI TypeScript passed on Node 20.19.5 with 8192 MiB and incremental disabled. Scoped ESLint matches the four baseline warnings with zero errors; scoped task normalization and diff checks passed. Independent connected-code and reproduction review found no actionable issue and inspected rather than reran the runtime suites.
ADR required: no durable rule change. Bandit is inapplicable to this TypeScript test/task-only correction. Full hosted shard and browser E2E were not run locally; fresh CI is required. All selected APIs were mocked; no backend, database, Docker, restore or recovery execution occurred. Five owned dependency links and two empty directories were removed with memory, evidence and dependency targets preserved. The existing Change summary waiver and earlier validation limits remain. No CI rerun POST, merge or base update occurred for this correction.