Context
The operator reported that the portal app is unstable after the first resolved #12204 foundation PRs. The visible failure on /news/tickets is a dynamic-import failure for apps/portal/view/news/tickets/MainContainer.mjs.
This ticket is intentionally narrow: the tickets tab is stuck because the shared timeline view-glue moved under apps/portal/view/content/, but its framework imports still walk up one directory too far.
Duplicate sweep completed before filing:
ask_knowledge_base(query='Portal CanvasWrapper TimelineCanvas import path dynamic import tickets tab regression', type='ticket') surfaced older TimelineCanvas regressions, but none for the new shared-content import path break.
rg across resources/content/{issues,archive/issues,discussions,archive/discussions} found historical dynamic-import and TimelineCanvas tickets, but no equivalent active ticket for the CanvasWrapper / TimelineCanvas post-move path regression.
- GitHub issue searches for the exact dynamic-import symptom and
Portal.view.content.CanvasWrapper returned no duplicate.
The Problem
Portal.view.news.TabContainer lazy-loads the tickets tab via module: () => import('./tickets/MainContainer.mjs'). Live NL verification shows /news/tickets active but the tab body item remains isLoading: true and no Portal.view.news.tickets.MainContainer component mounts.
A direct ESM import falsifier exposes the underlying dependency break:
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/Users/Shared/codex/neomjs/src/container/Base.mjs' imported from /Users/Shared/codex/neomjs/neo/apps/portal/view/content/CanvasWrapper.mjs
From apps/portal/view/content/, ../../../../../src/... resolves above the repo root. The correct depth is ../../../../src/....
The Architectural Reality
The #12204 foundation refactor promotes shared timeline view-glue out of apps/portal/view/news/tickets/ and into apps/portal/view/content/.
Current source anchors:
apps/portal/view/news/tickets/MainContainer.mjs:1 imports ../../content/CanvasWrapper.mjs.
apps/portal/view/content/CanvasWrapper.mjs:1 imports ../../../../../src/container/Base.mjs, which resolves one level too high from its new directory.
apps/portal/view/content/TimelineCanvas.mjs:1 has the same depth issue for ../../../../../src/app/SharedCanvas.mjs.
- The relevant styling surface already moved to
resources/scss/src/apps/portal/content/CanvasWrapper.scss; ticket work must keep the shared content SCSS honored and must not silently strand theme-specific portal ticket overrides under resources/scss/theme-neo-{light,dark}/apps/portal/news/tickets/.
The Fix
- Correct the shared content imports in
apps/portal/view/content/CanvasWrapper.mjs and apps/portal/view/content/TimelineCanvas.mjs from five parent traversals to four.
- Re-run the ESM import-chain falsifier until it reaches the expected runtime-only
Neo global boundary instead of ERR_MODULE_NOT_FOUND.
- Re-verify
/news/tickets through Neural Link: the tickets main component must mount and the tab body must leave isLoading.
- Check the portal SCSS paths touched by the move so the shared CanvasWrapper styling and existing light/dark ticket component overrides remain in the cascade.
Decision Record impact
none
Acceptance Criteria
Out of Scope
- Implementing PR or Discussion views from #12204.
- Chunked lazy-load tree work (#12217-#12219).
- Reworking the timeline parser, canvas physics, or route defaults.
- Broad theming redesign beyond preserving the moved/shared style surfaces.
Avoided Traps
- Do not hide the regression under the broad #12204 epic; this is a narrow import-path break with a concrete falsifier.
- Do not revert the shared content move from #12206; the move is the right shape, but its relative imports must be updated for the new directory.
- Do not treat the browser's
MainContainer.mjs dynamic-import error as proof that MainContainer.mjs itself is missing; dependency import failure surfaces at the lazy module boundary.
Related
- Parent epic: #12204
- Regression source area: #12206
- Open adjacent portal foundation lane: #12209
Handoff Retrieval Hints
portal tickets dynamic import CanvasWrapper TimelineCanvas relative path
apps/portal/view/content CanvasWrapper ../../../../../src ERR_MODULE_NOT_FOUND
NL /news/tickets isLoading true Portal.view.news.tickets.MainContainer not mounted
Context
The operator reported that the portal app is unstable after the first resolved #12204 foundation PRs. The visible failure on
/news/ticketsis a dynamic-import failure forapps/portal/view/news/tickets/MainContainer.mjs.This ticket is intentionally narrow: the tickets tab is stuck because the shared timeline view-glue moved under
apps/portal/view/content/, but its framework imports still walk up one directory too far.Duplicate sweep completed before filing:
ask_knowledge_base(query='Portal CanvasWrapper TimelineCanvas import path dynamic import tickets tab regression', type='ticket')surfaced older TimelineCanvas regressions, but none for the new shared-content import path break.rgacrossresources/content/{issues,archive/issues,discussions,archive/discussions}found historical dynamic-import and TimelineCanvas tickets, but no equivalent active ticket for theCanvasWrapper/TimelineCanvaspost-move path regression.Portal.view.content.CanvasWrapperreturned no duplicate.The Problem
Portal.view.news.TabContainerlazy-loads the tickets tab viamodule: () => import('./tickets/MainContainer.mjs'). Live NL verification shows/news/ticketsactive but the tab body item remainsisLoading: trueand noPortal.view.news.tickets.MainContainercomponent mounts.A direct ESM import falsifier exposes the underlying dependency break:
From
apps/portal/view/content/,../../../../../src/...resolves above the repo root. The correct depth is../../../../src/....The Architectural Reality
The #12204 foundation refactor promotes shared timeline view-glue out of
apps/portal/view/news/tickets/and intoapps/portal/view/content/.Current source anchors:
apps/portal/view/news/tickets/MainContainer.mjs:1imports../../content/CanvasWrapper.mjs.apps/portal/view/content/CanvasWrapper.mjs:1imports../../../../../src/container/Base.mjs, which resolves one level too high from its new directory.apps/portal/view/content/TimelineCanvas.mjs:1has the same depth issue for../../../../../src/app/SharedCanvas.mjs.resources/scss/src/apps/portal/content/CanvasWrapper.scss; ticket work must keep the shared content SCSS honored and must not silently strand theme-specific portal ticket overrides underresources/scss/theme-neo-{light,dark}/apps/portal/news/tickets/.The Fix
apps/portal/view/content/CanvasWrapper.mjsandapps/portal/view/content/TimelineCanvas.mjsfrom five parent traversals to four.Neoglobal boundary instead ofERR_MODULE_NOT_FOUND./news/ticketsthrough Neural Link: the tickets main component must mount and the tab body must leaveisLoading.Decision Record impact
none
Acceptance Criteria
node --input-type=module -e "await import('./apps/portal/view/news/tickets/MainContainer.mjs')"no longer fails withERR_MODULE_NOT_FOUNDforapps/portal/view/content/*imports./news/ticketsshowsPortal.view.news.tickets.MainContainermounted under the news tab instead of a permanent loading item.resources/scss/src/apps/portal/content/CanvasWrapper.scssand does not drop existing light/dark ticket component theme overrides.Out of Scope
Avoided Traps
MainContainer.mjsdynamic-import error as proof thatMainContainer.mjsitself is missing; dependency import failure surfaces at the lazy module boundary.Related
Handoff Retrieval Hints
portal tickets dynamic import CanvasWrapper TimelineCanvas relative pathapps/portal/view/content CanvasWrapper ../../../../../src ERR_MODULE_NOT_FOUNDNL /news/tickets isLoading true Portal.view.news.tickets.MainContainer not mounted