[GH-ISSUE #1174] [Bug] Selected package exports targets use extension and directory fallbacks #416

Closed
opened 2026-10-15 18:24:53 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 9, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/1174

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Evidence, artifacts, or reconstruction

Observed behavior

JavaScript application analysis substitutes an extension or directory index for a selected package exports target. With exports: "./file" and only file.js present, REA reports a resolved import relationship to file.js, although the selected target is absent and Node rejects the same input. The same failure occurs for exports: "./folder" with only folder/index.js, under both import and require loading.

Reproduction

Create this three-file fixture in a disposable directory. There is no file named node_modules/pkg/file.

main.mjs
node_modules/pkg/package.json
node_modules/pkg/file.js

main.mjs:

import 'pkg';

node_modules/pkg/package.json:

{"type":"module","exports":"./file"}

node_modules/pkg/file.js:

export const value = 1;

Run these commands, where fixture_dir is the absolute path of the disposable fixture:

npx -y rea-agents@6.1.0 analyze-javascript-application "$fixture_dir" --format json
node "$fixture_dir/main.mjs"

For a source checkout built with npm ci and npm run build:cached, replace the npx command with node scripts/rea.mjs analyze-javascript-application "$fixture_dir" --format json. Both tested builds reproduce this three-file case. The original fixture, which also contained relative ESM imports, reproduced the package-exports discrepancy through generic analyze as well.

For the directory variant, change the selected target to ./folder and replace the package file with folder/index.js. For the require variants, use main.cjs containing module.exports = require('pkg');, package type commonjs, and a module.exports = 1; target file. These variants were executed independently.

Expected behavior

A selected package exports target names the selected file, under both import and require loading. If the exact selected file is absent, retain the specifier and report a non-resolved outcome with resolved_path: null and a lookup limitation. Do not attach the relationship to an appended-extension file or a directory index. Keep exact-file exports resolution and legacy CommonJS main/directory fallbacks working.

Merged PR #606 states that an absent selected exports file must remain absent. Merged PR #575 distinguishes bare exports targets from legacy main/index fallbacks. Current tests/boundary/filesystem/javascriptPackageExportTargets.test.ts:139-215 compares both import and require target selection and unresolved outcomes with real Node, while src/application/javascript/JavaScriptArtifactPathResolution.test.ts:469-491 expects a missing exports target to remain not-found rather than use a package index. This report concerns that supported selected-target contract, rather than universal Node loader parity.

Impact and scope

The bounded fixtures produce incorrect resolved module identities in static application Evidence. Analysis completes, but the graph can direct investigation to a file the selected exports target does not load. This affects selected root exports targets under both import and require. No target execution, confidentiality, or isolation failure was observed in REA analysis.

Exact exports: "./file.js" controls passed on both builds and native Node. CommonJS legacy main: "./file" and main: "./folder" controls also passed, demonstrating that their extension/directory fallbacks remain valid. Wider production incidence and other loader profiles were not measured.

REA version

Latest published release rea-agents@6.1.0, confirmed with npm view rea-agents version; current default branch main at b34bdcdb2877be394c59c9cbf70269dc1841ff78, built successfully with npm ci and npm run build:cached.

Runtime and platform

Node.js v24.21.0, npm 11.19.0, macOS 27.0.1 build 26A434, arm64.

Target and artifact context

Inert local JavaScript directory fixtures with a root package exports entry. Native Node executed only the owned fixture modules for comparison. No binary-analysis provider was used.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

Both tested REA builds exit 0 and emit these semantic import-edge properties for the extension variant:

{"specifier":"pkg","resolved_path":"node_modules/pkg/file.js","resolution_status":"resolved"}

For the directory variant, both builds resolve node_modules/pkg/folder/index.js. Native Node exits 1 for every failing case: import extension gives ERR_MODULE_NOT_FOUND, import directory gives ERR_UNSUPPORTED_DIR_IMPORT, and both require variants give MODULE_NOT_FOUND. Each independently constructed variant failed once per tested REA build. The three-file import reduction was separately rerun on both builds. These are bounded fixture observations, not a production incidence estimate.

Typed outcome or recovery expected

A non-resolved relationship with the declared specifier, resolved_path: null, and an actionable missing-file or directory-target limitation. Correcting the selected target to the exact inventoried file should restore resolved package relationships without disabling legacy CommonJS fallbacks.

Analysis or suspected cause

Source inspection shows that the resolver passes selected exports back through full recursive candidate lookup. resolveCandidate at lines 314-330 uses appended extensions and directory candidates. The exports-specific flag changes URL handling but does not restrict these candidates. This is source-derived reasoning consistent with the executed observations, not a prescribed repair.

Additional context

No exact duplicate appeared in open/closed issue and PR searches covering extensionless ESM, extension/directory fallback, and exports exact/missing targets. The related merged PRs above concern different selection and precedence errors.

The original relative ESM imports ./dep and ./folder also receive fallback resolution, but they are excluded here because an exact-file contract for every relative-import artifact profile was not established. This single report isolates selected package exports target lookup, including its import/require and extension/directory variants.

Restoration should make each failing exports fixture unresolved while retaining the passing exact-file exports controls and CommonJS legacy main extension/directory controls. Native target resolution plus a file-kind check can independently check the selected target without executing analyzed modules; that comparison was verified on these fixtures.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: The bounded fixtures yield incorrect resolved module identities on a supported static package-analysis path. The graph is misleading for affected targets, while analysis remains available and no severe runtime or isolation failure was observed.
  • Workaround status: available
  • Workaround basis: A nonexecuting native-resolution check was verified on the fixture cases. For import, import.meta.resolve('pkg') plus a filesystem file-kind check exposes the absent or directory target; for require, require.resolve('pkg') rejects it. This independently checks affected relationships without modifying or executing the analyzed modules; the REA graph itself remains incorrect until corrected.
Originally created by @coygeek on GitHub (Oct 9, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/1174 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Evidence, artifacts, or reconstruction ### Observed behavior JavaScript application analysis substitutes an extension or directory index for a selected package `exports` target. With `exports: "./file"` and only `file.js` present, REA reports a resolved import relationship to `file.js`, although the selected target is absent and Node rejects the same input. The same failure occurs for `exports: "./folder"` with only `folder/index.js`, under both import and require loading. ### Reproduction Create this three-file fixture in a disposable directory. There is no file named `node_modules/pkg/file`. ```text main.mjs node_modules/pkg/package.json node_modules/pkg/file.js ``` `main.mjs`: ```js import 'pkg'; ``` `node_modules/pkg/package.json`: ```json {"type":"module","exports":"./file"} ``` `node_modules/pkg/file.js`: ```js export const value = 1; ``` Run these commands, where `fixture_dir` is the absolute path of the disposable fixture: ```sh npx -y rea-agents@6.1.0 analyze-javascript-application "$fixture_dir" --format json node "$fixture_dir/main.mjs" ``` For a source checkout built with `npm ci` and `npm run build:cached`, replace the npx command with `node scripts/rea.mjs analyze-javascript-application "$fixture_dir" --format json`. Both tested builds reproduce this three-file case. The original fixture, which also contained relative ESM imports, reproduced the package-exports discrepancy through generic `analyze` as well. For the directory variant, change the selected target to `./folder` and replace the package file with `folder/index.js`. For the require variants, use `main.cjs` containing `module.exports = require('pkg');`, package type `commonjs`, and a `module.exports = 1;` target file. These variants were executed independently. ### Expected behavior A selected package exports target names the selected file, under both import and require loading. If the exact selected file is absent, retain the specifier and report a non-resolved outcome with `resolved_path: null` and a lookup limitation. Do not attach the relationship to an appended-extension file or a directory index. Keep exact-file exports resolution and legacy CommonJS main/directory fallbacks working. Merged [PR #606](https://github.com/morluto/rea/pull/606) states that an absent selected exports file must remain absent. Merged [PR #575](https://github.com/morluto/rea/pull/575) distinguishes bare exports targets from legacy main/index fallbacks. Current `tests/boundary/filesystem/javascriptPackageExportTargets.test.ts:139-215` compares both import and require target selection and unresolved outcomes with real Node, while `src/application/javascript/JavaScriptArtifactPathResolution.test.ts:469-491` expects a missing exports target to remain `not-found` rather than use a package index. This report concerns that supported selected-target contract, rather than universal Node loader parity. ### Impact and scope The bounded fixtures produce incorrect resolved module identities in static application Evidence. Analysis completes, but the graph can direct investigation to a file the selected exports target does not load. This affects selected root exports targets under both import and require. No target execution, confidentiality, or isolation failure was observed in REA analysis. Exact `exports: "./file.js"` controls passed on both builds and native Node. CommonJS legacy `main: "./file"` and `main: "./folder"` controls also passed, demonstrating that their extension/directory fallbacks remain valid. Wider production incidence and other loader profiles were not measured. ### REA version Latest published release `rea-agents@6.1.0`, confirmed with `npm view rea-agents version`; current default branch `main` at `b34bdcdb2877be394c59c9cbf70269dc1841ff78`, built successfully with `npm ci` and `npm run build:cached`. ### Runtime and platform Node.js `v24.21.0`, npm `11.19.0`, macOS `27.0.1` build `26A434`, arm64. ### Target and artifact context Inert local JavaScript directory fixtures with a root package exports entry. Native Node executed only the owned fixture modules for comparison. No binary-analysis provider was used. ### Interface CLI ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence Both tested REA builds exit 0 and emit these semantic import-edge properties for the extension variant: ```json {"specifier":"pkg","resolved_path":"node_modules/pkg/file.js","resolution_status":"resolved"} ``` For the directory variant, both builds resolve `node_modules/pkg/folder/index.js`. Native Node exits 1 for every failing case: import extension gives `ERR_MODULE_NOT_FOUND`, import directory gives `ERR_UNSUPPORTED_DIR_IMPORT`, and both require variants give `MODULE_NOT_FOUND`. Each independently constructed variant failed once per tested REA build. The three-file import reduction was separately rerun on both builds. These are bounded fixture observations, not a production incidence estimate. ### Typed outcome or recovery expected A non-resolved relationship with the declared specifier, `resolved_path: null`, and an actionable missing-file or directory-target limitation. Correcting the selected target to the exact inventoried file should restore resolved package relationships without disabling legacy CommonJS fallbacks. ### Analysis or suspected cause Source inspection shows that the [resolver](https://github.com/morluto/rea/blob/b34bdcdb2877be394c59c9cbf70269dc1841ff78/src/application/javascript/JavaScriptArtifactPathResolution.ts#L380-L395) passes selected exports back through full recursive candidate lookup. `resolveCandidate` at lines 314-330 uses appended extensions and directory candidates. The exports-specific flag changes URL handling but does not restrict these candidates. This is source-derived reasoning consistent with the executed observations, not a prescribed repair. ### Additional context No exact duplicate appeared in open/closed issue and PR searches covering extensionless ESM, extension/directory fallback, and exports exact/missing targets. The related merged PRs above concern different selection and precedence errors. The original relative ESM imports `./dep` and `./folder` also receive fallback resolution, but they are excluded here because an exact-file contract for every relative-import artifact profile was not established. This single report isolates selected package exports target lookup, including its import/require and extension/directory variants. Restoration should make each failing exports fixture unresolved while retaining the passing exact-file exports controls and CommonJS legacy main extension/directory controls. Native target resolution plus a file-kind check can independently check the selected target without executing analyzed modules; that comparison was verified on these fixtures. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: The bounded fixtures yield incorrect resolved module identities on a supported static package-analysis path. The graph is misleading for affected targets, while analysis remains available and no severe runtime or isolation failure was observed. - Workaround status: available - Workaround basis: A nonexecuting native-resolution check was verified on the fixture cases. For import, `import.meta.resolve('pkg')` plus a filesystem file-kind check exposes the absent or directory target; for require, `require.resolve('pkg')` rejects it. This independently checks affected relationships without modifying or executing the analyzed modules; the REA graph itself remains incorrect until corrected.
bsakaguchi 2026-10-15 18:24:53 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#416
No description provided.