LearnNewsExamplesServices
Frontmatter
id15723
titlePackaging guard needs syntax-accurate literal import scanning
stateClosed
labels
bugaitestingbuild
assigneesneo-gpt
createdAtJul 22, 2026, 4:38 PM
updatedAtJul 22, 2026, 7:16 PM
githubUrlhttps://github.com/neomjs/neo/issues/15723
authorneo-gpt-emmy
commentsCount3
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[x] 15714 Harden packaged first-paint receipt guards
blocking[]
closedAtJul 22, 2026, 7:16 PM

Packaging guard needs syntax-accurate literal import scanning

Closed Backlog/active-chunk-8 bugaitestingbuild
neo-gpt-emmy
neo-gpt-emmy commented on Jul 22, 2026, 4:38 PM

Summary

The packaged-import contract added through #15714 / PR #15718 has two coupled gaps:

  1. a literal dynamic parent-root import such as import('../ai/...') or import('../src/...') escapes the current static-only guard; and
  2. the shared extractLiteralImportSpecifiers() helper is not yet syntax-accurate. Its comment-stripped regex also recognizes import-shaped text inside ordinary string literals.

The second fact falsifies the original one-line repair. Projecting the current helper directly into the parent-root assertion would catch the deployment dead end while creating false-positive build failures.

Why this matters

A forbidden parent-root dependency can pass the packaging test yet remain absent from the packaged local closure. The installed application then fails only when that dynamic import executes from app.asar.

Conversely, an ordinary string containing import-shaped prose can currently be misclassified as a dependency. A guard built directly on that output can reject valid source. Both are packaging-boundary correctness failures; neither should be deferred to an installed runtime.

Verified current reality

At merged dev@86fc94cd87b569f8359bae75ed2d52e4974936c3:

  • extractLiteralImportSpecifiers() removes comments and applies IMPORT_SPECIFIER_RE; it is a bounded regex scanner, not a JavaScript syntax parser.
  • import('../ai/example.mjs') yields ['../ai/example.mjs'].
  • an ordinary string containing import('../src/string.mjs') also yields ['../src/string.mjs'].
  • non-literal import(runtimeSpecifier) remains outside the declared contract.
  • the parent-root assertion still matches only static from '../ai|src/...' syntax.
  • acorn is already a direct repository dependency. An executable parse probe distinguishes the literal dynamic import as an ImportExpression while the lookalike remains an ordinary VariableDeclaration.

ADR-0034 §§2.5–2.6 require an explicit packaged source graph and dev/prod parity. They do not justify either a false-negative dependency guard or a false-positive regex approximation.

Intended solution

Harden the shared literal-import extractor so it derives specifiers from JavaScript syntax rather than import-shaped text. Use the repository's existing parser substrate (currently acorn) or an equivalently precise already-owned lexer; do not add a second regex scanner.

The shared extractor must cover:

  • static import declarations;
  • side-effect imports;
  • re-export sources;
  • string-literal dynamic import() expressions; and
  • the staged .mjs, .cjs, and .js source forms consumed by packaging.

It must ignore comments, ordinary strings/template text, and non-literal dynamic specifiers. Once that authority is syntax-accurate, project its output into the existing packaging-test seam and explicitly reject normalized ../ai/ and ../src/ specifiers. Keep local ./*.mjs closure behavior unchanged.

Acceptance criteria

  • A synthetic import('../ai/example.mjs') fails the parent-root guard.
  • A synthetic import('../src/example.mjs') fails the parent-root guard.
  • Static default/named imports, side-effect imports, and re-exports from those parent roots remain rejected.
  • extractLiteralImportSpecifiers() derives imports from syntax, not import-lookalike text.
  • Ordinary strings and template text containing import(...), from '...', or export ... from '...' do not create specifiers.
  • Line/block comments containing import examples do not create specifiers.
  • Non-literal dynamic imports remain outside the bounded contract.
  • Existing bare-package discovery remains green across staged .mjs, .cjs, and .js sources.
  • Local ./*.mjs closure discovery and the installed app.asar import witness remain green.
  • No parallel import regex/parser is introduced; all three consumers use the corrected shared extractor.
  • Focused tests demonstrate both red-before failures: dynamic parent-root false negative and ordinary-string false positive, followed by green-after evidence.

Out of scope

  • Bundling all of ai/ or src/.
  • Resolving computed or otherwise non-literal dynamic specifiers.
  • Reworking the packaged local dependency model established by #15714.
  • Changes to runtime import semantics outside the packaging guard.
  • Adding a new parser dependency when an owned parser can satisfy the contract.

Negative-ROI check

Positive ROI after narrowing. The scanner is already shared by local-closure and bare-package discovery, so repairing syntax accuracy at that authority avoids three divergent guards. A full packer redesign or a second parser would be negative ROI.

Related substrate

Duplicate and content sweep

Live sweep completed at 2026-07-22T14:37:35Z across the latest open issue queue plus targeted issue/PR searches for dynamic parent-root imports and packaged app.asar guards. No duplicate ticket or implementation was found. Revalidated after PR #15718 merged.

Decision record

No new architecture decision. This ticket repairs the syntax authority used to enforce the packaged source boundary already established by #15714 and governed by ADR-0034.