[GH-ISSUE #3907] [Bug] Vite dependency arrays resolve the wrong file after a spread #1518

Closed
opened 2026-10-16 21:06:30 +00:00 by bsakaguchi · 1 comment
Owner

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

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

Static application analysis can publish a resolved dynamic-import edge to last.js when a Vite dependency helper actually selects middle-b.js. The indexer treats a spread as one unknown array slot, then assigns definite indexes to following elements. A spread can contribute multiple elements. This is a bounded incorrect dependency result, established from source without running REA.

The source proof derives ['./first.js', undefined, './last.js'] from the three AST elements. vitePreloadDependencySpecifiers directly indexes that table for [0, 2]; inspectCall emits ./first.js and ./last.js references. Same-container lookup finds last.js, so the graph publishes resolved_path: "last.js" and resolution_status: "resolved" for the wrong dependency.

The initial investigation executed one isolated Node language control. The spread helper and flat-array control both returned ["./first.js","./middle-b.js"]. This establishes fixture semantics only. REA output, serialized Evidence, exit status, and timing were not observed.

Reproduction

These public REA steps are proposed and unexecuted. Use the baseline below with a working runtime. In a fresh local application directory /tmp/rea-vite-spread, create package.json containing {"type":"module"} and main.mjs containing:

const __vite__mapDeps = (i, m = __vite__mapDeps,
  d = (m.f || (m.f = ["./first.js", ...["./middle-a.js", "./middle-b.js"], "./last.js"]))) =>
  i.map(i => d[i]);
export const dependencies = __vite__mapDeps([0, 2]);

Create sibling files first.js containing export default "first";, middle-a.js containing export default "middle-a";, middle-b.js containing export default "middle-b";, and last.js containing export default "last";. All targets are ordinary valid JavaScript files in the same container.

Call MCP analyze_javascript_application with:

{"input_path":"/tmp/rea-vite-spread","format":"directory","integrity_policy":"fail"}

Inspect graph edges with properties.kind === "dynamic-import" attributed to the helper call in main.mjs. For a control, change only the initializer to ["./first.js", "./middle-a.js", "./middle-b.js", "./last.js"]. Both forms select the same paths for [0, 2]. No browser, Electron, network, or native engine is required.

Expected behavior

Retain first.js at index 0. Index 2 must resolve to middle-b.js if literal spreads are expanded, or remain explicitly unknown if spread expansion is unsupported. It must not resolve to last.js. The flat-array control must preserve its correct relationship. Documented static import recovery and existing Vite tests require unsupported table slots to remain unknown; a static relationship does not promise application execution.

Impact and scope

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: The public source path creates a wrong resolved dependency for a valid bounded source form. No operation-wide failure, artifact modification, or production prevalence is established.

REA version

Reviewed release: rea-agents-6.5.0, revision 3b79af28e80785afce9f5998d8f03289402a1847. The source review compared fetched main at cf0a38ad9774ee9acff3164052688f7a58a1c72c; the relevant indexing, extraction, and projection remained unchanged. The language control used Node v26.10.0, Darwin arm64. REA runtime and cross-platform behavior were not tested; no platform dependency was identified in the source path.

Runtime and platform

REA runtime reproduction was not run. Runtime and platform details for any smaller premise checks are recorded in the version/environment field above. Real-provider versions and end-to-end output are NOT_ENOUGH_INFO because no provider was launched.

Target and artifact context

Local module directory containing a Vite-style dependency helper with a literal array spread and four sibling JavaScript targets.

Interface

MCP

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

The initial Node control separately establishes the expected language result. REA runtime reproduction was not run. The public path and guards below come from source inspection.

Public reachability starts at src/server/registerElectronTools.ts:99-115, which parses the request defined in src/domain/javascript/javascriptApplicationAnalysis.ts:26-33 and calls analyzeJavaScriptApplicationValidated. The explicit absolute directory, format, and integrity fields are accepted. src/application/javascript/JavaScriptApplicationService.ts:55-69 → JavaScriptArtifactReconstruction.ts:150-175 → JavaScriptArtifactAnalysis.ts:158-198 reconstructs the artifact and submits included JavaScript files to the source worker. src/composition/javascriptAnalysisWorkerProcess.ts:27-47 parses and checkpoints static facts; src/domain/javascript/javascriptStaticAnalysis.ts:89-112 supplies the Vite table to traversal. Call extraction in javascriptStaticAnalysisCalls.ts:78-84,521-543 retains each specifier and call location.

The fixture passes the indexer's guards: one helper declaration, second parameter m through an assignment pattern, exactly one member assignment of an array expression to m.f, and no disallowed helper escape. The escape scan skips the helper and permits its declaration and direct call. The call supplies literal safe nonnegative indexes and no cache override. All files are tiny UTF-8 JavaScript and remain selected.

src/application/javascript/JavaScriptArtifactGraphBuilder.ts:125-143 projects findings through JavaScriptArtifactGraphFindings.ts:54-65,444-538. This is a non-worker module-import reference. JavaScriptArtifactPathResolution.ts:309-330,1387-1402 performs exact lookup and admits the inventoried same-container target. last.js differs from main.mjs, so self-reference omission cannot hide the incorrect edge. These final graph files are under src/application/javascript/.

Typed outcome or recovery expected

For the exact spread fixture, no edge attributed to __vite__mapDeps([0, 2]) may resolve to last.js. Preserve first.js; represent the second dependency as middle-b.js or meaningful uncertainty. The flat-array control must still resolve both correct files. Empty, single-element, and multiple-element spreads distinguish general index preservation from a special case. These acceptance checks are unexecuted and prescribe no repair.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: The public source path creates a wrong resolved dependency for a valid bounded source form. No operation-wide failure, artifact modification, or production prevalence is established.
  • Workaround status: unverified
  • Workaround basis: No supported option was demonstrated that preserves the original artifact while correcting the dependency. Manual inspection is possible; flattening the source is a control, not a verified workaround for the original input.
Originally created by @coygeek on GitHub (Oct 15, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3907 ## 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 Static application analysis can publish a resolved dynamic-import edge to `last.js` when a Vite dependency helper actually selects `middle-b.js`. The indexer treats a spread as one unknown array slot, then assigns definite indexes to following elements. A spread can contribute multiple elements. This is a bounded incorrect dependency result, established from source without running REA. The source proof derives `['./first.js', undefined, './last.js']` from the three AST elements. `vitePreloadDependencySpecifiers` directly indexes that table for `[0, 2]`; `inspectCall` emits `./first.js` and `./last.js` references. Same-container lookup finds `last.js`, so the graph publishes `resolved_path: "last.js"` and `resolution_status: "resolved"` for the wrong dependency. The initial investigation executed one isolated Node language control. The spread helper and flat-array control both returned `["./first.js","./middle-b.js"]`. This establishes fixture semantics only. REA output, serialized Evidence, exit status, and timing were not observed. ## Reproduction These public REA steps are proposed and unexecuted. Use the baseline below with a working runtime. In a fresh local application directory `/tmp/rea-vite-spread`, create `package.json` containing `{"type":"module"}` and `main.mjs` containing: ```js const __vite__mapDeps = (i, m = __vite__mapDeps, d = (m.f || (m.f = ["./first.js", ...["./middle-a.js", "./middle-b.js"], "./last.js"]))) => i.map(i => d[i]); export const dependencies = __vite__mapDeps([0, 2]); ``` Create sibling files `first.js` containing `export default "first";`, `middle-a.js` containing `export default "middle-a";`, `middle-b.js` containing `export default "middle-b";`, and `last.js` containing `export default "last";`. All targets are ordinary valid JavaScript files in the same container. Call MCP `analyze_javascript_application` with: ```json {"input_path":"/tmp/rea-vite-spread","format":"directory","integrity_policy":"fail"} ``` Inspect graph edges with `properties.kind === "dynamic-import"` attributed to the helper call in `main.mjs`. For a control, change only the initializer to `["./first.js", "./middle-a.js", "./middle-b.js", "./last.js"]`. Both forms select the same paths for `[0, 2]`. No browser, Electron, network, or native engine is required. ## Expected behavior Retain `first.js` at index 0. Index 2 must resolve to `middle-b.js` if literal spreads are expanded, or remain explicitly unknown if spread expansion is unsupported. It must not resolve to `last.js`. The flat-array control must preserve its correct relationship. Documented static import recovery and existing Vite tests require unsupported table slots to remain unknown; a static relationship does not promise application execution. ## Impact and scope - Impact level: P2 - Assessment status: supported - Impact basis: The public source path creates a wrong resolved dependency for a valid bounded source form. No operation-wide failure, artifact modification, or production prevalence is established. ## REA version Reviewed release: `rea-agents-6.5.0`, revision `3b79af28e80785afce9f5998d8f03289402a1847`. The source review compared fetched main at `cf0a38ad9774ee9acff3164052688f7a58a1c72c`; the relevant indexing, extraction, and projection remained unchanged. The language control used Node `v26.10.0`, Darwin arm64. REA runtime and cross-platform behavior were not tested; no platform dependency was identified in the source path. ## Runtime and platform REA runtime reproduction was not run. Runtime and platform details for any smaller premise checks are recorded in the version/environment field above. Real-provider versions and end-to-end output are NOT_ENOUGH_INFO because no provider was launched. ## Target and artifact context Local module directory containing a Vite-style dependency helper with a literal array spread and four sibling JavaScript targets. ## Interface MCP ## Earliest failure stage Native analysis or reconstruction ## Relevant output or evidence - Expected source: [docs/javascript-artifact-reconstruction.md:200-223](https://github.com/morluto/rea/blob/3b79af28e80785afce9f5998d8f03289402a1847/docs/javascript-artifact-reconstruction.md#L200-L223) documents inert import recovery; [src/domain/javascript/javascriptVitePreloadDependencies.test.ts:5-33](https://github.com/morluto/rea/blob/3b79af28e80785afce9f5998d8f03289402a1847/src/domain/javascript/javascriptVitePreloadDependencies.test.ts#L5-L33) requires unknown slots and supplies a flat-array control. - Failure source: [src/domain/javascript/javascriptStaticAnalysisCalls.ts:295-408](https://github.com/morluto/rea/blob/3b79af28e80785afce9f5998d8f03289402a1847/src/domain/javascript/javascriptStaticAnalysisCalls.ts#L295-L408) contains the accepted call and spread-to-slot indexing; [src/application/javascript/JavaScriptArtifactGraphFindings.ts:154-189](https://github.com/morluto/rea/blob/3b79af28e80785afce9f5998d8f03289402a1847/src/application/javascript/JavaScriptArtifactGraphFindings.ts#L154-L189) publishes resolved import properties. - Evidence provenance: static - Local verification: static-proof - Reproduction completeness: complete The initial Node control separately establishes the expected language result. REA runtime reproduction was not run. The public path and guards below come from source inspection. Public reachability starts at `src/server/registerElectronTools.ts:99-115`, which parses the request defined in `src/domain/javascript/javascriptApplicationAnalysis.ts:26-33` and calls `analyzeJavaScriptApplicationValidated`. The explicit absolute directory, format, and integrity fields are accepted. `src/application/javascript/JavaScriptApplicationService.ts:55-69` → `JavaScriptArtifactReconstruction.ts:150-175` → `JavaScriptArtifactAnalysis.ts:158-198` reconstructs the artifact and submits included JavaScript files to the source worker. `src/composition/javascriptAnalysisWorkerProcess.ts:27-47` parses and checkpoints static facts; `src/domain/javascript/javascriptStaticAnalysis.ts:89-112` supplies the Vite table to traversal. Call extraction in `javascriptStaticAnalysisCalls.ts:78-84,521-543` retains each specifier and call location. The fixture passes the indexer's guards: one helper declaration, second parameter `m` through an assignment pattern, exactly one member assignment of an array expression to `m.f`, and no disallowed helper escape. The escape scan skips the helper and permits its declaration and direct call. The call supplies literal safe nonnegative indexes and no cache override. All files are tiny UTF-8 JavaScript and remain selected. `src/application/javascript/JavaScriptArtifactGraphBuilder.ts:125-143` projects findings through `JavaScriptArtifactGraphFindings.ts:54-65,444-538`. This is a non-worker module-import reference. `JavaScriptArtifactPathResolution.ts:309-330,1387-1402` performs exact lookup and admits the inventoried same-container target. `last.js` differs from `main.mjs`, so self-reference omission cannot hide the incorrect edge. These final graph files are under `src/application/javascript/`. ## Typed outcome or recovery expected For the exact spread fixture, no edge attributed to `__vite__mapDeps([0, 2])` may resolve to `last.js`. Preserve `first.js`; represent the second dependency as `middle-b.js` or meaningful uncertainty. The flat-array control must still resolve both correct files. Empty, single-element, and multiple-element spreads distinguish general index preservation from a special case. These acceptance checks are unexecuted and prescribe no repair. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: The public source path creates a wrong resolved dependency for a valid bounded source form. No operation-wide failure, artifact modification, or production prevalence is established. - Workaround status: unverified - Workaround basis: No supported option was demonstrated that preserves the original artifact while correcting the dependency. Manual inspection is possible; flattening the source is a control, not a verified workaround for the original input.
Author
Owner

@Sriram-PR commented on GitHub (Oct 15, 2026):

I'll take this one. Reproduced on main (6fcfc5b) through analyze-javascript-application: the spread fixture resolves index 2 to last.js, the flat control to middle-b.js. indexVitePreloadDependencyTable maps the spread to a single undefined slot, so every later entry is off by however many elements the spread adds. Plan: keep the entries before the first spread and leave every index from the spread onward unknown (no guessing at spread length), plus a regression test next to the existing Vite table tests. PR shortly.

<!-- gh-comment-id:6186896822 --> @Sriram-PR commented on GitHub (Oct 15, 2026): I'll take this one. Reproduced on main (6fcfc5b) through `analyze-javascript-application`: the spread fixture resolves index 2 to `last.js`, the flat control to `middle-b.js`. `indexVitePreloadDependencyTable` maps the spread to a single `undefined` slot, so every later entry is off by however many elements the spread adds. Plan: keep the entries before the first spread and leave every index from the spread onward unknown (no guessing at spread length), plus a regression test next to the existing Vite table tests. PR shortly.
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#1518
No description provided.