Skip to content

fix(app): retrying dynamic imports — the tunnel-truncation class (#1459b, current-main slice) - #1474

Merged
jeonghun-jj-lee merged 4 commits into
mainfrom
slice/retry-import
Sep 23, 2026
Merged

jeonghun-jj-lee merged 4 commits into
mainfrom
slice/retry-import

Conversation

@aarontrowbridge

Copy link
Copy Markdown
Member

A current-main slice per the #1465 doctrine: small, test-guarded (7 contract tests), manifest-clean (drift gate PASS).

The class (live-verified on the reference fleet today, NOT reproducible in the rig — localhost has no tunnel): the ssh tunnel restarts on network transitions and each restart kills in-flight responses MID-STREAM. A lazy chunk crossing a restart gets a cleanly-truncated body (observed: 2,884 of 28,497 bytes — the resource ledger's encodedBodySize names it). Chromium's module map then caches the failure for the document's life: every later import of the same URL throws without a network request — the boundary catches it, the route navigates, and the outlet holds the loading UI forever. This is the complete mechanism behind every stuck-launch report today; the tunnel watchdog logged consecutive-000 probe windows lasting minutes, and a single immediate retry also drowned in the storm.

The fix: retryImport (utils/retry-import.ts) — parses the failing URL from the truncation error, re-imports it CACHE-BUSTED (a fresh module-map key; chained busts strip the previous query), backing off 1s→2s→4s→8s→16s (~31s storm ride-out). Wired at all 8 dynamic-import sites (NewSession, EmptyWorkspaceLanding, the status popover bodies, the command dialogs). Transient-only: real errors rethrow untouched.

Diagnostics behind it: CDP fresh-target import tests + Chromium's Log domain (strict module MIME failure naming text/html) + the resource-ledger size check — the differential that separated cache, content, and transport in one pass. Full story in the session ledger + #1459.

…ass (current-main slice). The fleet's ssh tunnel restarts on network transitions (launchd KeepAlive) and kills every in-flight tunneled response MID-STREAM; a lazily-imported chunk crossing a restart gets a cleanly-truncated body (observed live: 2,884 of 28,497 bytes) and Chromium's module map caches the failure FOR THE DOCUMENT'S LIFE — every later import of the same URL throws 'Failed to fetch dynamically imported module' WITHOUT a network request: the new-session launch frozen in the loading hold forever (live-verified root cause of the stuck-loading arc; the rig has no tunnel so it never sees the class). retryImport parses the failing URL, re-imports it cache-busted (fresh module-map key) with backoff 1s→2s→4s→8s→16s (~31s of transport-storm ride-out; observed watchdog windows last minutes — a single immediate retry drowned in the storm's first beat); chained busts strip the previous query. Wired at all 8 dynamic-import sites. Transient-only: real errors rethrow. 7 contract tests (importer injected — the engine's import() never runs in the suite). Manifest: files + classification registered, drift gate PASS.
@coderabbitai

coderabbitai Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 37 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 2d40411b-e852-4966-bebf-dd72842fdbb7

📥 Commits

Reviewing files that changed from the base of the PR and between 7063bf6 and b1cc891.

📒 Files selected for processing (6)
  • packages/app-bundle/manifest.json
  • packages/app-bundle/overlay/packages/app/src/app.tsx
  • packages/app-bundle/overlay/packages/app/src/components/status-popover.tsx
  • packages/app-bundle/overlay/packages/app/src/pages/session/use-session-commands.tsx
  • packages/app-bundle/overlay/packages/app/src/utils/retry-import.test.ts
  • packages/app-bundle/overlay/packages/app/src/utils/retry-import.ts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@jeonghun-jj-lee

Copy link
Copy Markdown
Contributor

Reconciled this branch with current main at #1472 (12d03e3) without force-pushing. The retry behavior is now intentionally bounded: five delays totaling 31 seconds. It preserves every original query parameter while replacing only retry, rethrows non-transient errors unchanged, and remains limited to the eight selected lazy-import boundaries rather than claiming universal dynamic-import coverage.\n\nLocal evidence on reconciled head 917cd4d4:\n- retry contract suite: 3/3\n- app typecheck: clean\n- node packages/app-bundle/scripts/drift_gate.mjs: PASS\n- diff hygiene: clean\n- broad app suite reproduces the pre-existing 12 Happy DOM MutationObserver failures in unchanged observe-element-offset tests; CI remains the mechanical gate for this PR.\n\nGitHub CI is now being monitored. This PR remains unmerged and still needs a human approval after a green run.

@jeonghun-jj-lee

Copy link
Copy Markdown
Contributor

main advanced to 7063bf63 (#1490) during the first CI watch. I merged that current base normally, without conflicts or force-push; reconciled head is now b1cc891d. The new base touched only .github/workflows/release.yml and AGENTS.md; the six-file retry delta is unchanged.\n\nI reran the focused retry contract suite (3/3), app typecheck, and drift gate before restarting CI. This PR remains unmerged and awaits the new CI run plus human approval.

@jeonghun-jj-lee jeonghun-jj-lee left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm

@jeonghun-jj-lee
jeonghun-jj-lee merged commit ee7f383 into main Sep 23, 2026
12 checks passed
@jeonghun-jj-lee
jeonghun-jj-lee deleted the slice/retry-import branch September 23, 2026 22:14
jeonghun-jj-lee added a commit that referenced this pull request Sep 24, 2026
…MPDIR self-pollution fix) (#1520)

* fix: recover session reliability regressions (#1472)

* fix(packaging): enforce known fixes before CI advisory

* fix(app): #1466 restore parent Files Changed invalidation

* test(app): cover all #1466 file edit events

* fix(app): #1467 bound mirror and session warming

* fix(packaging): migrate #832 shared-state guard

* fix(app): guard session warm scheduler keys

* fix(app): repair #1466 review findings

---------

Co-authored-by: amicode-ci <ci@amicode.local>

* ci: publish release VSIXes to Open VSX Registry (#1490)

* ci: publish release VSIXes to Open VSX Registry

* ci: decouple Open VSX publish from Marketplace step outcome

* fix(app): #1458 — the empty-workspace landing's titlebar portals crash every real boot (current-main slice, manifest-clean) (#1473)

* fix(app): #1458 — the empty-workspace landing's titlebar portals rendered SessionChatsDropdown/StatusPopoverV2 (per-directory sync-context readers) at the "/" route, which never sits inside a SyncProvider; at real-boot timing the no-directory window renders the landing briefly on EVERY boot and the useSync() throw killed the whole route tree — including the reactive landing effect, so no draft was ever created and the app stayed frozen at "/". Portals removed, content kept; a guard test pins the landing module free of directory-scoped context components (the unit-suite trap: mocked contexts pass while the real boot crashes — caught live by the e2e rig). Manifest: files + classification updated (drift gate PASS).

* fix(app): #1458 follow-up — the guard test matched raw text and tripped on the fix's own explanatory comment (which names the removed components); assert the import graph instead. All green: 2 pass, drift gate PASS.

* fix(app): render empty landing without directory context

---------

Co-authored-by: amicode-ci <ci@amicode.local>

* fix(app): retrying dynamic imports — the tunnel-truncation class (#1459b, current-main slice) (#1474)

* fix(app): #1459b — retrying dynamic imports, the tunnel-truncation class (current-main slice). The fleet's ssh tunnel restarts on network transitions (launchd KeepAlive) and kills every in-flight tunneled response MID-STREAM; a lazily-imported chunk crossing a restart gets a cleanly-truncated body (observed live: 2,884 of 28,497 bytes) and Chromium's module map caches the failure FOR THE DOCUMENT'S LIFE — every later import of the same URL throws 'Failed to fetch dynamically imported module' WITHOUT a network request: the new-session launch frozen in the loading hold forever (live-verified root cause of the stuck-loading arc; the rig has no tunnel so it never sees the class). retryImport parses the failing URL, re-imports it cache-busted (fresh module-map key) with backoff 1s→2s→4s→8s→16s (~31s of transport-storm ride-out; observed watchdog windows last minutes — a single immediate retry drowned in the storm's first beat); chained busts strip the previous query. Wired at all 8 dynamic-import sites. Transient-only: real errors rethrow. 7 contract tests (importer injected — the engine's import() never runs in the suite). Manifest: files + classification registered, drift gate PASS.

* fix(app): bound dynamic import retries

---------

Co-authored-by: amicode-ci <ci@amicode.local>

* fix: follow up on compaction review findings (#1463)

* fix: preserve interrupted compaction output

* fix(app): localize compaction failure toast

* fix(core): surface compaction runner errors

* fix(engine): send final-step directive as user input

* test(engine): cover manual compaction runner request

* chore(app-bundle): refresh overlay manifest

* fix(server): map compact runner failures

---------

Co-authored-by: amicode-ci <ci@amicode.local>

* fix(app): recover deferred session mirror pruning (#1502)

Co-authored-by: amicode-ci <ci@amicode.local>

* fix: bound and isolate background session warming (#1501)

* fix: bound background session warming

* test: cover prewarmer batch scheduling

* refactor: share session prewarmer batching

* test: cover multi-row prewarmer batches

* fix: parallelize bulk lineage warming

* fix: release warm slots after prefetch

---------

Co-authored-by: amicode-ci <ci@amicode.local>

* fix(test): stop instruction.test.ts leaking AGENTS.md into $TMPDIR

The 'does not walk past a secondary directory' test wrote AGENTS.md to
path.dirname(tmpdirScoped()) === os.tmpdir(), an UNSCOPED file in the shared
$TMPDIR root that (a) was never cleaned up and (b) poisoned every sibling test
nesting tmp dirs under $TMPDIR — the loader walks up and finds it. Nest the
secondary under its own scoped parent so the 'above' AGENTS.md lands in an
auto-cleaned dir. findUp for a secondary dir stops at the dir itself (stop=dir),
so no git root is needed. Fixes 2 instruction.test.ts failures.

---------

Co-authored-by: amicode-ci <ci@amicode.local>
Co-authored-by: Jack Champagne <43344745+jack-champagne@users.noreply.github.com>
Co-authored-by: Aaron Trowbridge <47730232+aarontrowbridge@users.noreply.github.com>
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.

2 participants