[GH-ISSUE #1911] [Bug] JavaScript admission reserves 80% of parent capacity for any later file #638

Closed
opened 2026-10-15 18:26:51 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @N0zoM1z0 on GitHub (Oct 11, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/1911

Before submitting

  • I searched open and closed issues and pull requests for related work.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Evidence, artifacts, or reconstruction.

Observed behavior

Analyzing two inert JavaScript files discards the earlier file's completed semantic graph when one later file remains, even though the later file is only export const tiny = 1;. Static and module facts survive. The reported recovery action directs the caller to worker memory, while the rejection comes from the parent's admission budget.

Reproduction

  1. Create a-large.mjs containing 800 declarations of the following form, substituting the index in the name and numeric literal:
    export function method_0(input) { const value = input + 0; const pair = { value }; return pair.value; }
    
  2. Add z-tiny.mjs containing export const tiny = 1;.
  3. Run NODE_OPTIONS=--max-old-space-size=512 rea analyze <directory> --format json.
  4. Inspect the earlier file's analysis_failure and the returned semantic graph separately from parsing statistics.

Expected behavior

Derive the future-static reservation from the actual checkpoint protocol bound and remaining source count. Preserve all applicable total-heap, transfer-expansion, decoding and cleanup constraints. Reject only results that exceed those resource-derived admission limits, and explain the parent-side constraint accurately.

Impact and scope

The two files parse successfully (17,609 visited AST nodes, zero parse failures), but the first file's semantic graph is missing. The CLI finishes successfully with explicit partial evidence. This is parent-side admission, not worker heap exhaustion. Shared CLI/MCP behavior needs regression coverage.

REA version

898d5096f94fe1ed3ea7d091455e638cc7d23bfd.

Runtime and platform

Linux x86_64; Node.js 24.18.0. The reproduction used one CPU and a 3-GiB process-tree limit, with a 512-MiB parent old-space setting and the default 1,024-MiB worker setting.

Target and artifact context

An inert generated ES module of 86,179 bytes and a 23-byte ES module; directory input.

Interface

CLI; the same admission owner serves MCP.

Earliest failure stage

Transport or result projection.

Relevant output or evidence

Semantic graph for a-large.mjs exceeds the parent's remaining result budget; static and module facts were retained

Reported limits: parent_result_budget_bytes=192120876, graph_transfer_bytes=17946120, graph_records=24007. No method_0 semantic node is returned.

Analysis or suspected cause

Source-derived finding: JavaScriptAnalysisWorker.#remainingResultBudget reserves 80% of the original parent budget whenever any future source remains. That fraction does not distinguish one future file from many. Previously retained static bytes reduce the reserve, but the earlier graph is not reconsidered after later static checkpoints finish. The protocol already bounds each static checkpoint to 8 MiB, and its owner already estimates retained expansion.

The diagnostic reports the total parent budget rather than the effective admission budget and uses a generic worker-memory recovery action.

Additional context

This is distinct from #1847's historical worker-heap failure; current-main checks no longer reproduce that particular worker failure on the original input. Related: #1848 (caller-selected sources) and #1065 (bounded results).

Originally created by @N0zoM1z0 on GitHub (Oct 11, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/1911 ### Before submitting - [x] I searched open and closed issues and pull requests for related work. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Evidence, artifacts, or reconstruction. ### Observed behavior Analyzing two inert JavaScript files discards the earlier file's completed semantic graph when one later file remains, even though the later file is only `export const tiny = 1;`. Static and module facts survive. The reported recovery action directs the caller to worker memory, while the rejection comes from the parent's admission budget. ### Reproduction 1. Create `a-large.mjs` containing 800 declarations of the following form, substituting the index in the name and numeric literal: ```js export function method_0(input) { const value = input + 0; const pair = { value }; return pair.value; } ``` 2. Add `z-tiny.mjs` containing `export const tiny = 1;`. 3. Run `NODE_OPTIONS=--max-old-space-size=512 rea analyze <directory> --format json`. 4. Inspect the earlier file's `analysis_failure` and the returned semantic graph separately from parsing statistics. ### Expected behavior Derive the future-static reservation from the actual checkpoint protocol bound and remaining source count. Preserve all applicable total-heap, transfer-expansion, decoding and cleanup constraints. Reject only results that exceed those resource-derived admission limits, and explain the parent-side constraint accurately. ### Impact and scope The two files parse successfully (17,609 visited AST nodes, zero parse failures), but the first file's semantic graph is missing. The CLI finishes successfully with explicit partial evidence. This is parent-side admission, not worker heap exhaustion. Shared CLI/MCP behavior needs regression coverage. ### REA version `898d5096f94fe1ed3ea7d091455e638cc7d23bfd`. ### Runtime and platform Linux x86_64; Node.js 24.18.0. The reproduction used one CPU and a 3-GiB process-tree limit, with a 512-MiB parent old-space setting and the default 1,024-MiB worker setting. ### Target and artifact context An inert generated ES module of 86,179 bytes and a 23-byte ES module; directory input. ### Interface CLI; the same admission owner serves MCP. ### Earliest failure stage Transport or result projection. ### Relevant output or evidence `Semantic graph for a-large.mjs exceeds the parent's remaining result budget; static and module facts were retained` Reported limits: `parent_result_budget_bytes=192120876`, `graph_transfer_bytes=17946120`, `graph_records=24007`. No `method_0` semantic node is returned. ### Analysis or suspected cause Source-derived finding: `JavaScriptAnalysisWorker.#remainingResultBudget` reserves 80% of the original parent budget whenever any future source remains. That fraction does not distinguish one future file from many. Previously retained static bytes reduce the reserve, but the earlier graph is not reconsidered after later static checkpoints finish. The protocol already bounds each static checkpoint to 8 MiB, and its owner already estimates retained expansion. The diagnostic reports the total parent budget rather than the effective admission budget and uses a generic worker-memory recovery action. ### Additional context This is distinct from #1847's historical worker-heap failure; current-main checks no longer reproduce that particular worker failure on the original input. Related: #1848 (caller-selected sources) and #1065 (bounded results).
Author
Owner

@N0zoM1z0 commented on GitHub (Oct 11, 2026):

Confirmed the owning admission rule with an inert 400-function ES module and a later small ES module: the affected base returns no semantic functions for the earlier file. The focused public-CLI regression fails on the base.

The resource owner runs one sequential worker, so the reservation should protect the next possible static checkpoint at the existing protocol limit (8 MiB times the same retained-expansion factor used on receipt). Previously accepted facts remain charged to the retained-result ledger, and total/live-heap, decode, transfer, cancellation and cleanup protections remain in place. Reserving the maximum for every unexamined file would introduce a new false rejection for directories with many small files; the regression therefore also includes ten later source files.

Parent-side admission failures now report the effective available result budget and the retained module/graph expansion estimates, and direct the caller to the facts that actually survived. A tighter parent-heap case still rejects the graph with an explicit partial result; increasing the worker heap alone does not solve that parent-side limit.

Final validation includes the public CLI, real stdio MCP cancellation/resource/recovery workflows, and unchanged-input verification before preparing the PR.

<!-- gh-comment-id:6111766656 --> @N0zoM1z0 commented on GitHub (Oct 11, 2026): Confirmed the owning admission rule with an inert 400-function ES module and a later small ES module: the affected base returns no semantic functions for the earlier file. The focused public-CLI regression fails on the base. The resource owner runs one sequential worker, so the reservation should protect the next possible static checkpoint at the existing protocol limit (8 MiB times the same retained-expansion factor used on receipt). Previously accepted facts remain charged to the retained-result ledger, and total/live-heap, decode, transfer, cancellation and cleanup protections remain in place. Reserving the maximum for every unexamined file would introduce a new false rejection for directories with many small files; the regression therefore also includes ten later source files. Parent-side admission failures now report the effective available result budget and the retained module/graph expansion estimates, and direct the caller to the facts that actually survived. A tighter parent-heap case still rejects the graph with an explicit partial result; increasing the worker heap alone does not solve that parent-side limit. Final validation includes the public CLI, real stdio MCP cancellation/resource/recovery workflows, and unchanged-input verification before preparing the PR.
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#638
No description provided.