Skip to content

test(missions): identify owned catalog read cancellations - #1247

Merged
pascalandr merged 1 commit into
devfrom
fix/native-family-catalog-cancellation
Nov 1, 2026
Merged

pascalandr merged 1 commit into
devfrom
fix/native-family-catalog-cancellation

Conversation

@pascalandr

Copy link
Copy Markdown
Contributor

Summary

Fix the native-family browser fixture's accounting of intentionally superseded panel-extension catalog reads. Keep production behavior and every existing navigation error assertion unchanged. A uniquely tagged production list call is classified separately only after its own signal is aborted and its full API promise rejects with a native DOMException named AbortError.

Root cause and investigation

CI run 41261807276 on #1244 head 0e5820489aeda482369157eaf530e63e26a6fcb1 failed deferred ordinary-child navigation cannot overwrite a newer sibling selection with /api/panel-extensions net::ERR_ABORTED. The full failed job log was inspected. Its uploaded browser artifact contains only the fixture-daemon log; that log records clean shutdown and zero active optimizer contexts, and contains no per-family request receipts.

A controlled real-shell reproduction on current dev (abb14f83c6168b9eb04001359574e5d31ecc72d0) held the first catalog request and admitted the initial SSE open after that read began. It reproduced the exact failing assertion, before page cleanup. The observed native signal-abort stack is:

EventSource.onopen → event transport connected callback → ServerEvents.emitTransportStatus → usePanelExtensions.refresh → clear → AbortController.abort.

The hook intentionally replaces an optional catalog read on transport reconnection, visibility or instance changes. A sibling selection is incidental to this particular cancellation. The fixture and production catalog/transport sources match dev and #1244; the isolated native-family fixture owns its server/cache and is independent of #1244's changed fixtures. #1244 is unchanged. The separately assigned git-history failure was not investigated.

Correction and safety checks

  • Observe the real panelExtensionsApi.list promise, including response-body parsing, and return that same promise to production callers. Preserve the original rejection.
  • Tag its synchronously dispatched fetch with a fixture-only read identity header, restoring window.fetch immediately before yielding. Missing/unknown identities fail closed.
  • Classify only same-origin, exact catalog GETs with ERR_ABORTED and a matching owning-signal/native-AbortError outcome. Retain raw failures and identity-qualified cancellation receipts in the existing diagnostic output.
  • Serve the empty catalog as the API's actual [] shape instead of the catch-all {} response.
  • Leave the existing errors/failures assertions, other collectors and production lifecycle untouched. Add no sleeps, retries or console suppression.

The new regression drives the real transport-status dispatcher and production hook, holds a catalog read, supersedes it, and requires a successful replacement response. It then injects an actual browser network abort on the same URL and error code, followed by an unrelated aborted fetch: both must remain in failures while the owner cancellation remains separately identified and present in the raw log.

Before/after evidence

  • The held-initial-catalog/SSE-open control fails with the original exact CI assertion on unchanged dev; the same control passes after the correction, with its raw abort retained as read 1's proven cancellation and the sibling draft preserved.
  • The committed regression fails before the collector correction with the exact catalog ERR_ABORTED assertion and passes afterward.
  • Final regression diagnostics contain three raw aborts: one classified owner cancellation, one catalog network failure without an owner-cancellation receipt, and one unrelated failure. The latter two remain in failures.

Validation

  • node --import tsx --test --test-concurrency=1 tests/browser/mission-native-family.test.ts: three runs, 12/12 each (36/36), including all existing real-shell/native-dispatcher callers of the shared collector.
  • fixture-wiring.test.ts + fixture-shutdown.test.ts: 8/8.
  • npm run typecheck --workspace @codenomad/ui: pass.
  • git diff --check: pass.

Windows, Chromium 153. Test-only change; public help is unaffected.

The native-family fixture counts every panel catalog ERR_ABORTED as a
navigation failure. Holding the initial catalog request until SSE opens
reproduces the exact CI assertion on unchanged dev: the real connected
callback supersedes the read through usePanelExtensions.clear, before
navigation or page cleanup. The hook's optional-read cancellation is valid.

Observe the production list call's owning signal and full API outcome,
including body parsing, without changing its result or rejection. A
fixture-only request identity binds the native browser failure to that
specific call. Keep raw failures and explicit cancellation receipts; only
an aborted owning signal plus a native AbortError classifies the exact
catalog GET as expected. Unknown identities and network aborts stay failed.
Serve the empty catalog with its correct array response shape.

The new real-shell regression fails before this collector correction and
passes after it. It verifies a successful superseding read and proves a
network abort on the same catalog URL, plus an unrelated abort, remain in
the failure array. All existing error assertions and production code stay
unchanged. Three full native-family runs pass (12 tests each), fixture
wiring/shutdown checks pass (8 tests), and UI typecheck and whitespace
checks pass. PR #1244 is left unchanged; git-history is outside this work.

@pascalandr pascalandr left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0: 0 · P1: 0 · P2: 0 · P3: 0 — Verdict: PASS (no actionable findings).

Reviewed commit dbcc9058f7354d6b4742b3794b1cca22c66dca4a against dev abb14f83c6168b9eb04001359574e5d31ecc72d0.

Scope and correctness

  • The diff changes only packages/ui/tests/browser/fixtures/mission-native-family.tsx and packages/ui/tests/browser/mission-native-family.test.ts. Production code, existing navigation/error assertions, and PR #1244 are unchanged.
  • Traced the collector and all its test callers, RightPanel → usePanelExtensions.refresh/clear → panelExtensionsApi.list → authenticatedFetch → native fetch/body parsing, and the EventSource → transport-status dispatcher lifecycle. Read the applicable agent, browser-fixture, panel-extension, native-event and cache conventions.
  • The request identity is assigned only during the real list call's synchronous fetch dispatch, and the original fetch is restored before yielding. Classification requires the exact same-origin catalog GET, net::ERR_ABORTED, its recorded identity, its own aborted signal, and a native DOMException named AbortError from the full API promise. The original promise/rejection reaches production unchanged. Unknown identities and observation failures fail closed; every raw request failure stays recorded.
  • The regression uses the real shell, components and dispatcher with held requests and response/failure events. No production hooks, broad cancellation exclusions, new sleeps/retries, or extra abstractions were introduced. The empty installed-extension response now has the correct array shape.

Independent validation

Windows, Node 25.2.1, Chromium 153.0.8010.12.

  • node --import tsx --test --test-concurrency=1 tests/browser/mission-native-family.test.ts: four complete runs, 12/12 each (48/48), covering every existing caller of the shared collector. Run durations were approximately 103, 125, 135 and 115 seconds.
  • fixture-wiring.test.ts + fixture-shutdown.test.ts: 8/8 passed. Additional cache, navigation-budget and diagnostic-boundary checks: 14/14 passed.
  • panel-extensions.test.ts: 14/14 passed, including real routes and lifecycle fencing.
  • npm run typecheck --workspace @codenomad/ui: passed. git diff --check and base-to-head whitespace check: passed.
  • Review-only runtime overlays outside the checkout reproduced the original deferred-child assertion on dev by holding the initial catalog read until the real initial SSE open. The only failure was /api/panel-extensions net::ERR_ABORTED; selection and the newer sibling draft were already correct. The identical gated scenario passed with this correction, retaining that raw failure as read 1's proven cancellation.
  • Removing only the new collector classification at runtime makes the committed supersession regression fail with the exact catalog-abort assertion. The unchanged head passes, and its diagnostics retain three raw aborts: one owner cancellation plus the same-URL network abort and unrelated abort, with the latter two still in failures.
  • An additional review-only real streaming-response control canceled the body after response headers: the full API promise supplied the native cancellation receipt and the replacement succeeded. Missing and unknown identity controls on the same catalog URL remained failures.

Evidence and runtime-overlay script are under C:\Users\Admin\AppData\Local\codenomad-agent-scratch\review-1247-evidence and review-1247-overlay.mjs. These controls change only runtime-loaded test sources; checkout files and branches are untouched. Validated fixture shutdown receipts show zero pending requests, zero active optimizer contexts, matching created/disposed contexts and a closed listener.

No oversized touched files: fixture 160 lines, test 653 lines. The reviewed branch remains clean at the exact commit above. No commits, pushes, merges, branch switches, or shared-daemon operations were performed. Repository-wide CI was still pending when checked; this is a COMMENT review, not a CI completion claim.

@pascalandr
pascalandr merged commit 4e4090b into dev Nov 1, 2026
43 of 44 checks passed
@pascalandr
pascalandr deleted the fix/native-family-catalog-cancellation branch November 1, 2026 03:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant