[GH-ISSUE #3383] [Bug] Historical-source import ignores CommonJS package main and selects an unrelated index #1251

Closed
opened 2026-10-16 21:03:21 +00:00 by bsakaguchi · 0 comments
Owner

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

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

import-reference-source resolves a relative CommonJS directory import to dep/index.js even when dep/package.json selects actual.js through its main field. The CLI exits successfully and reports the wrong file as a parsed internal dependency with no parse failure. Analysis of the saved historical graph can therefore follow code that the supplied CommonJS source does not load.

The initial run and an independent rerun both produced the mismatch. All four fixture files, including the package manifest and the actual entry point, are included in the inventory. Changing the fixture's call to require("./dep/actual.js") yields the correct internal dependency on dep/actual.js with no parse failures.

Reproduction

  1. Start from a clean checkout of https://github.com/morluto/rea at revision 8dde6370d0809ad04cda3342d4e6f290f48aa063, then install the locked dependencies and build the runtime:
npm ci
npm run build:cached
  1. Run this isolated reproduction from the repository root. It creates every input file and an isolated configuration home. The Node control resolves the import without executing any source file.
rea_cli="$PWD/scripts/rea.mjs"
work="$(mktemp -d "${TMPDIR:-.}/rea-import.XXXXXX")"
mkdir -p "$work/source/dep" "$work/home"
printf '%s\n' 'require("./dep");' > "$work/source/main.cjs"
printf '%s\n' '{"main":"actual.js"}' > "$work/source/dep/package.json"
printf '%s\n' 'module.exports = "real dependency";' > "$work/source/dep/actual.js"
printf '%s\n' 'module.exports = "wrong dependency";' > "$work/source/dep/index.js"
HOME="$work/home" XDG_CONFIG_HOME="$work/home" node "$rea_cli" import-reference-source "$work/source" --json > "$work/graph.json"
node - "$work/source" "$work/graph.json" <<'NODE'
const fs = require("node:fs");
const path = require("node:path");
const { createRequire } = require("node:module");
const root = fs.realpathSync(process.argv[2]);
const graph = JSON.parse(fs.readFileSync(process.argv[3], "utf8"));
console.log("Node target:", path.relative(root, createRequire(path.join(root, "main.cjs")).resolve("./dep")));
console.log("REA relationships:", JSON.stringify(graph.relationships));
console.log("Parse failures:", JSON.stringify(graph.parse_failures));
NODE
rm -rf "$work"
  1. Compare the Node target with the REA relationship. The observed Node target is dep/actual.js, while REA reports dep/index.js as an internal, parsed dependency and reports no parse failures.

Expected behavior

For this CommonJS directory import, the graph should identify dep/actual.js as the dependency, matching the package's declared entry point and Node's resolution of the source. If the importer cannot establish that selection, it should preserve an unresolved or unknown relationship instead of asserting that the different index file is the resolved dependency. This ordinary relative directory import requires no installed dependency, package export map, custom loader, or target execution.

docs/cli.md:223 documents the complete historical-source graph. tests/boundary/cli/referenceSourceDirectoryImports.test.ts:67 uses Node's resolver as the oracle for CommonJS directory imports, and tests/boundary/cli/referenceSourceDirectoryImports.test.ts:96 requires matching public CLI dependency targets. docs/tool-design.md:57 requires unresolved relationships and uncertainty to remain distinct from established facts.

Impact and scope

Impact level: P2. The supported assessment is that a local CommonJS package with a non-index main entry point receives a wrong dependency in its historical graph. The source and manifest bytes remain available, and the demonstrated resolver control provides a bounded way to recover the intended target.

Workaround status: available. The executed Node resolve-only control finds dep/actual.js without executing the package or changing the historical source. It can guide interpretation of this dependency, although it does not correct the saved graph.

REA version

6.4.0 (main at 8dde6370d0)

Runtime and platform

Node.js v26.10.0; macOS 27.0.1 arm64. Dependencies and the compiled CLI runtime were already present for the observed reproduction. No native analysis provider is required.

Target and artifact context

A local CommonJS source directory containing main.cjs, dep/package.json, dep/actual.js, and dep/index.js. The package manifest declares actual.js as its main entry point, and the two JavaScript dependency files contain distinct exported strings. The result is a historical-source graph with all four files inventoried.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

The successful CLI import and the resolve-only Node control produced:

Node target: dep/actual.js
REA relationships: [{"from_path":"main.cjs","to":"dep/index.js","kind":"requires","resolution":"internal","parse_state":"parsed"}]
Parse failures: []

Typed outcome or recovery expected

With the supplied files unchanged, the graph must identify dep/actual.js or explicitly preserve unresolved selection rather than report dep/index.js as the known dependency. Keep the demonstrated explicit-file control using require("./dep/actual.js") resolving to dep/actual.js with no parse failures. Also retain a directory-import control without a package manifest and with dep/index.js present, so restoration does not disable the supported index fallback.

Analysis or suspected cause

Source-derived reasoning: src/application/ReferenceSourceImportEntries.ts:97 resolves an internal import from path candidates without consulting the inventoried package's entry-point declaration. src/application/ReferenceSourceImportEntries.ts:164 records the selected index as the resolved target. This reasoning is consistent with the executed import output and the resolve-only Node control; no implementation repair is claimed here.

Additional context

Related completed report #2020 concerns an empty package main preventing valid index fallback in analyze-javascript-application; this report concerns a non-empty main ignored by import-reference-source.

Related completed report #1761 concerns sibling node_modules files overriding package exports in application analysis; this report concerns a relative directory import and a legacy package main in historical-source import.

Related completed report #1174 concerns extension and directory fallbacks for selected package exports targets in application analysis; this report requires selecting the declared legacy main before falling back to an index.

Originally created by @coygeek on GitHub (Oct 14, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3383 ### 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 `import-reference-source` resolves a relative CommonJS directory import to `dep/index.js` even when `dep/package.json` selects `actual.js` through its `main` field. The CLI exits successfully and reports the wrong file as a parsed internal dependency with no parse failure. Analysis of the saved historical graph can therefore follow code that the supplied CommonJS source does not load. The initial run and an independent rerun both produced the mismatch. All four fixture files, including the package manifest and the actual entry point, are included in the inventory. Changing the fixture's call to `require("./dep/actual.js")` yields the correct internal dependency on `dep/actual.js` with no parse failures. ### Reproduction 1. Start from a clean checkout of `https://github.com/morluto/rea` at revision `8dde6370d0809ad04cda3342d4e6f290f48aa063`, then install the locked dependencies and build the runtime: ```sh npm ci npm run build:cached ``` 2. Run this isolated reproduction from the repository root. It creates every input file and an isolated configuration home. The Node control resolves the import without executing any source file. ```sh rea_cli="$PWD/scripts/rea.mjs" work="$(mktemp -d "${TMPDIR:-.}/rea-import.XXXXXX")" mkdir -p "$work/source/dep" "$work/home" printf '%s\n' 'require("./dep");' > "$work/source/main.cjs" printf '%s\n' '{"main":"actual.js"}' > "$work/source/dep/package.json" printf '%s\n' 'module.exports = "real dependency";' > "$work/source/dep/actual.js" printf '%s\n' 'module.exports = "wrong dependency";' > "$work/source/dep/index.js" HOME="$work/home" XDG_CONFIG_HOME="$work/home" node "$rea_cli" import-reference-source "$work/source" --json > "$work/graph.json" node - "$work/source" "$work/graph.json" <<'NODE' const fs = require("node:fs"); const path = require("node:path"); const { createRequire } = require("node:module"); const root = fs.realpathSync(process.argv[2]); const graph = JSON.parse(fs.readFileSync(process.argv[3], "utf8")); console.log("Node target:", path.relative(root, createRequire(path.join(root, "main.cjs")).resolve("./dep"))); console.log("REA relationships:", JSON.stringify(graph.relationships)); console.log("Parse failures:", JSON.stringify(graph.parse_failures)); NODE rm -rf "$work" ``` 3. Compare the Node target with the REA relationship. The observed Node target is `dep/actual.js`, while REA reports `dep/index.js` as an internal, parsed dependency and reports no parse failures. ### Expected behavior For this CommonJS directory import, the graph should identify `dep/actual.js` as the dependency, matching the package's declared entry point and Node's resolution of the source. If the importer cannot establish that selection, it should preserve an unresolved or unknown relationship instead of asserting that the different index file is the resolved dependency. This ordinary relative directory import requires no installed dependency, package export map, custom loader, or target execution. `docs/cli.md:223` documents the complete historical-source graph. `tests/boundary/cli/referenceSourceDirectoryImports.test.ts:67` uses Node's resolver as the oracle for CommonJS directory imports, and `tests/boundary/cli/referenceSourceDirectoryImports.test.ts:96` requires matching public CLI dependency targets. `docs/tool-design.md:57` requires unresolved relationships and uncertainty to remain distinct from established facts. ### Impact and scope Impact level: P2. The supported assessment is that a local CommonJS package with a non-index main entry point receives a wrong dependency in its historical graph. The source and manifest bytes remain available, and the demonstrated resolver control provides a bounded way to recover the intended target. Workaround status: available. The executed Node resolve-only control finds `dep/actual.js` without executing the package or changing the historical source. It can guide interpretation of this dependency, although it does not correct the saved graph. ### REA version 6.4.0 (main at 8dde6370d0809ad04cda3342d4e6f290f48aa063) ### Runtime and platform Node.js v26.10.0; macOS 27.0.1 arm64. Dependencies and the compiled CLI runtime were already present for the observed reproduction. No native analysis provider is required. ### Target and artifact context A local CommonJS source directory containing `main.cjs`, `dep/package.json`, `dep/actual.js`, and `dep/index.js`. The package manifest declares `actual.js` as its main entry point, and the two JavaScript dependency files contain distinct exported strings. The result is a historical-source graph with all four files inventoried. ### Interface CLI ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence The successful CLI import and the resolve-only Node control produced: ```text Node target: dep/actual.js REA relationships: [{"from_path":"main.cjs","to":"dep/index.js","kind":"requires","resolution":"internal","parse_state":"parsed"}] Parse failures: [] ``` ### Typed outcome or recovery expected With the supplied files unchanged, the graph must identify `dep/actual.js` or explicitly preserve unresolved selection rather than report `dep/index.js` as the known dependency. Keep the demonstrated explicit-file control using `require("./dep/actual.js")` resolving to `dep/actual.js` with no parse failures. Also retain a directory-import control without a package manifest and with `dep/index.js` present, so restoration does not disable the supported index fallback. ### Analysis or suspected cause Source-derived reasoning: `src/application/ReferenceSourceImportEntries.ts:97` resolves an internal import from path candidates without consulting the inventoried package's entry-point declaration. `src/application/ReferenceSourceImportEntries.ts:164` records the selected index as the resolved target. This reasoning is consistent with the executed import output and the resolve-only Node control; no implementation repair is claimed here. ### Additional context Related completed report [#2020](https://github.com/morluto/rea/issues/2020) concerns an empty package main preventing valid index fallback in `analyze-javascript-application`; this report concerns a non-empty main ignored by `import-reference-source`. Related completed report [#1761](https://github.com/morluto/rea/issues/1761) concerns sibling `node_modules` files overriding package exports in application analysis; this report concerns a relative directory import and a legacy package main in historical-source import. Related completed report [#1174](https://github.com/morluto/rea/issues/1174) concerns extension and directory fallbacks for selected package exports targets in application analysis; this report requires selecting the declared legacy main before falling back to an index.
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#1251
No description provided.