LearnNewsExamplesServices
Frontmatter
id17931
titleA dist/esm workspace fixture proves imports resolve, but never boots the app
stateClosed
labels
bugai
assigneesneo-opus-grace
createdAtAug 31, 2026, 11:15 AM
updatedAtSep 15, 2026, 9:20 AM
githubUrlhttps://github.com/neomjs/neo/issues/17931
authorneo-opus-grace
commentsCount5
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[x] 17971 Every consumer dist/esm build fails on a computed root no workspace can supply
blocking[]
closedAtSep 15, 2026, 9:20 AM

A dist/esm workspace fixture proves imports resolve, but never boots the app

neo-opus-grace
neo-opus-grace commented on Aug 31, 2026, 11:15 AM

The gap

#17921 fixed three defects that made a workspace dist/esm build emit a tree the app worker could not load, and added a build-time guard that fails when an emitted import does not resolve. Its AC-4 asked for more than that guard delivers:

A greenfield workspace fixture (apps + one extra source root) builds dist/esm and the produced app boots headlessly — the app worker reaches Neo.apps with the main view mounted.

The PR for #17921 delivered the first half. test/playwright/unit/buildScripts/esmWorkspaceBuild.spec.mjs creates a greenfield workspace, runs the real buildScripts/build/esmodules.mjs over it, and asserts every emitted import resolves. It does not boot the output.

This ticket owns the boot arm, carved out so the three shipped defects were not held behind a materially heavier fixture.

Why the boot arm is worth its own cost

Resolution is a necessary condition for booting, not a sufficient one. The existing fixture proves every specifier points at a file that exists; it cannot see a neo-config.json whose basePath resolves but addresses the wrong tree, a worker that starts from the wrong root, or two disjoint copies of the engine registering classes into namespaces the running runtime never reads. That last one is the failure mode described in #17921's defect 1, and it is invisible to a path-existence check because every path involved exists.

The boot arm is also the only thing that would have caught the whole class before a consumer did — #17921 notes that apparently no workspace exercises dist/esm today, which is precisely why three independent defects accumulated in it unnoticed.

Acceptance Criteria

  • A greenfield workspace fixture (apps/ plus at least one extra source root declared via neo.esmSourceRoots) is built through the real dist/esm build, using the actual engine rather than the stub the current fixture copies.
  • The produced app is served and loaded headlessly; the app worker reaches Neo.apps with the main view mounted.
  • A mutation control proves the arm can fail: reverting the import-rewrite quote class (or otherwise re-introducing a split module graph) must red the boot assertion, not merely the build.
  • The fixture's runtime cost is stated, and it is placed in a suite that actually runs in CI. test/playwright/unit is the only Engine suite CI currently executes alongside components; an e2e-shaped placement would not run.
  • Scope-transferred from #17943 (2026-08-31, @neo-gpt-emmy's RA-1 on PR #17957): in that same installed-engine output, HtmlTemplateProcessor loads and parses a template, so the arm proves the module works rather than that a path exists. #17943 shipped the artifact this needs (dist/parse5.mjs is now published); its own ACs could never reach here, because this fixture is the only thing that builds a real installed engine. Both consumers of the bundle are then covered: the build-time one by AC-1 (an installed engine that cannot start the build fails it) and the runtime one by this arm.

Scope transfer in (2026-08-31). #17943's AC-2 and AC-3 moved here rather than sitting un-closable on a ticket whose PR delivered everything else. They are struck through there with a pointer to this ticket. Nothing else about #17931's premise changed.

Notes for whoever takes this

  • The existing esmWorkspaceBuild.spec.mjs is the natural starting point; it already builds a workspace end to end and cleans up after itself.
  • Using the real engine rather than a stub is the expensive part — the current fixture deliberately stubs it because path arithmetic needs no real engine, and Terser over the full src/ tree adds minutes.
  • Related surface: #17918 (runtime-side dist-root derivation for absolute mounts) exercises the same mount shape at a different layer.

Origin

Carved from #17921 AC-4 during its implementation, rather than reported as met. The three transform defects and the build-time resolution guard shipped; this arm did not.

tobiu cross-referenced by PR #17927 on Aug 31, 2026, 12:49 PM
tobiu unassigned from @neo-opus-grace on Sep 1, 2026, 10:07 AM
tobiu referenced in commit c2cf498 - "test(e2e): the packed engine builds a greenfield dist/esm workspace, and both page forms boot (#17931) (#18718) on Sep 15, 2026, 9:20 AM
tobiu closed this issue on Sep 15, 2026, 9:20 AM