LearnNewsExamplesServices
Frontmatter
id17918
titleDist CSS and Font Awesome roots die on absolute mounts — substring(6) is relative-only
stateOpen
labels
bugaicore
assigneesneo-opus-vega
createdAtAug 31, 2026, 8:52 AM
updatedAtAug 31, 2026, 12:23 PM
githubUrlhttps://github.com/neomjs/neo/issues/17918
authorneo-opus-vega
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]

Dist CSS and Font Awesome roots die on absolute mounts — substring(6) is relative-only

neo-opus-vega
neo-opus-vega commented on Aug 31, 2026, 8:52 AM

Context

The defect is real and engine-wide: the absolute-mount config shape is legal per the D#17886 contract cells, and the current derivation black-pages it. What this ticket is NOT anymore: a deployment blocker. The consumer workspace that originally hit it has conformed to the canonical position-relative shape (verified on vanilla dev: source + both webpack dist environments + SharedWorker session join), so no live deployment depends on this fix.

Implementation is gated, not scheduled: PR #17919 delivered a complete candidate implementation and was closed Drop+Supersede (implementation-before-authority — D#17886's path contract has open gates 5/6/8 and #17884 is [PROVISIONAL_UNGRADUATED]). The salvage is pinned: branch vega/17918-dist-absolute-roots @ b5d1ed4b4c carries getAbsoluteDistRoot()/getCssRoot()/getFontAwesomePath(), the eight derivation/settlement spec arms, and the Font Awesome mutation witness. When D#17886 graduates and #17884 authorizes, that slice is the starting point — under whatever contract shape graduation lands, which may subsume rather than adopt it.

The Problem

src/main/addon/Stylesheet.mjs derives every dist CSS/resource root as basePath.substring(6) at three sites (:55 Font Awesome non-dev branch, :78 addGlobalCss, :105 addThemeFiles). The formula means "strip one ../../ hop" — correct only for the engine's own relative serving, where the page lives inside dist/<env>/apps/<app>/ and basePath is a relative climb. An absolute mount (basePath: '/<mount>/', one index per app OUTSIDE dist — a fixed-mount server arrangement) becomes udio/…: every sheet 404s and the mount never completes.

The Architectural Reality

The relative invariant: rootPath addresses "two levels above the page", and the css tree hangs at <root>/dist/<env>/css (dist-mode pages already sit inside dist/<env>, making rootPath BE the dist root). The absolute-mount equivalent is direct: basePath + (env.startsWith('dist/') ? env : 'dist/' + env) + '/'. Same target for the Font Awesome resources branch (resources/fontawesome-free/** is copied into each dist tree — verified in the D#17886 matrix).

The Fix

One private helper on the addon returning the absolute dist root when basePath is absolute (/-prefixed or fully qualified), null otherwise; the three sites use it and keep their existing relative arithmetic byte-identical when it returns null. No config surface changes; no behavior change for any of the 158 relative-basePath configs.

Decision Record impact: aligned-with #17884/D#17886 (interim repair the converged contract later subsumes; the fixture's mount-escape red control is the acceptance instrument).

Contract Ledger

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
Dist CSS root derivation (addGlobalCss, addThemeFiles) src/main/addon/Stylesheet.mjs#getCssRoot (folds getAbsoluteDistRoot) absolute/fully-qualified basePath → basePath + dist/<env>/; relative basePath → the pre-existing strip-one-hop arithmetic, byte-identical none — pure derivation, no config surface added helper JSDoc names both serving shapes per-site exact-URL spec arms; relative shapes pinned; reverted derivation reds every absolute arm
Font Awesome path (bundled envs) Stylesheet#getFontAwesomePath same dist-root derivation for the copied resources/fontawesome-free tree; source/dist/esm stay package-rooted (basePath + node_modules/…, absolute-safe already) none helper JSDoc dedicated spec arm across all four shapes; FA-site mutation reds it (measured)

Retirement: the #17884/D#17886 contract (one normalized root, per-surface matrix) subsumes both rows; these helpers become its first migration targets.

Acceptance Criteria

  • AC-1: with basePath: '/mount/' and environment: 'dist/<env>', all three sites emit /mount/dist/<env>/… URLs (unit spec per site, driving the real methods with a stubbed document).
  • AC-2: red control — the pre-fix derivation (substring(6)) on an absolute basePath is asserted broken by the same spec shape (mutation reds).
  • AC-3: relative-basePath emissions are byte-identical pre/post (spec pins the engine's own shapes: source, deeper app, dist-mode page).
  • AC-4: full unit suite green, fully-parallel.

Out of Scope

The #17884/D#17886 contract itself (root authority, normalize-once, per-surface matrix); the two dist/esm generator defects from the fixture (separate filing); any workspace-side change.

Related

#17884 (umbrella), D#17886 (fixture + contract), #17894 (the Stylesheet reject-reason repair that added main/addon/Stylesheet.spec.mjs, which these arms extend).

Origin Session ID: b51135ac-ec45-4689-ac45-0e99fb073069 Retrieval Hint: "dist css root absolute mount substring six interim repair"