[PR #1920] [CLOSED] fix(javascript): admit deferred semantic graphs after later sources #4910

Closed
opened 2026-10-31 00:56:40 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1920
Author: @jimpablo
Created: 10/11/2026
Status: ❌ Closed

Base: main ← Head: fix/javascript-parent-admission


📝 Commits (2)

  • 93df06e fix(javascript): admit deferred semantic graphs after later sources
  • 40096c1 fix(javascript): reserve only the next static checkpoint

📊 Changes

5 files changed (+365 additions, -64 deletions)

View changed files

📝 src/application/javascript/JavaScriptArtifactAnalysis.ts (+28 -1)
📝 src/domain/javascript/javascriptSourceAnalysis.ts (+14 -0)
📝 src/javascript/analysis/JavaScriptAnalysisTransfer.ts (+4 -1)
📝 src/javascript/analysis/JavaScriptAnalysisWorker.ts (+189 -62)
➕ tests/boundary/cli/javascriptAdmissionBudget.test.ts (+130 -0)

📄 Description

Summary

Fixes #1911. Fixes #1847.

On current main, the original #1847 worker-heap exhaustion no longer reproduces for the two generated wrappers (maintainer check at 898d5096, and this host did not see exhausted its heap). Directory analysis of the reduced two-file fixture from that investigation still drops the earlier file's completed semantic graph: the parent reserves 80% of its result budget whenever any later source remains, then the recovery text tells the caller to raise the worker heap.

This change reserves only the next static checkpoint (8 MiB, charged at the existing six-byte retention expansion), not one full checkpoint for every later file. A graph that fits once that reserve shrinks is kept and admitted after the later sources are analyzed. If the parent budget cannot start semantic analysis, the diagnostic names parent admission instead of the worker heap.

Problem and expected behavior

a-large.mjs (800 generated functions, objects, and bindings; 86,180 bytes) plus z-tiny.mjs (export const tiny = 1;) parses with 17,609 AST nodes and zero parse failures. Under NODE_OPTIONS=--max-old-space-size=512, the worker heap stays at the default 1,024 MiB and completes, but the parent reports:

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

with parent_result_budget_bytes=197848196, graph_transfer_bytes=17946120, graph_records=24007, and remediation that says to review worker memory. No method_0 semantic node is returned.

After this change the same command keeps syntax evidence and returns the semantic graph (12,005 nodes, 8,002 relations, including method_0) without truncation and without a worker-heap failure.

Change and scope

  • #futureStaticReserve replaces the 80% parent-budget reserve.
  • Graphs blocked only by that future-static reserve stay on the private runtime and are admitted by admitDeferredSemanticGraphs after later sources reduce the reserve. Graphs that still do not fit are rejected with the parent-admission error.
  • Worker heapMb default stays 1024. No MCP catalog, skill, or generated-doc change.

Contract and boundary impact

  • Semantic owner and earliest changed stage: parent result admission in JavaScriptAnalysisWorker, after the worker checkpoint.
  • CLI and MCP/tool-catalog contract: none. Same analyze / analyze-javascript-application result shape; admission failures now include parent_admission_budget_bytes and future_static_reserve_bytes, and their remediation no longer blames the worker heap.
  • Provider, bridge, target-format, or platform compatibility: none.
  • Evidence, artifact, provenance, or reconstruction contract: a semantic graph that was previously omitted is now retained when it fits the resource-derived budget. Observations, unknowns, and syntax facts are unchanged.
  • Process execution, authorization, cleanup, or containment impact: deferred transfer records stay in the existing private runtime until admission or close.
  • Generated metadata, package, or installation impact: none.

Evidence and regression coverage

  • Tests added or updated: tests/boundary/cli/javascriptAdmissionBudget.test.ts runs rea analyze through the compiled CLI, which spawns the production JavaScript analysis worker. The parent process is limited with NODE_OPTIONS=--max-old-space-size. The tests do not pass max_heap_mb, so the worker stays at the default 1024 MiB. Coverage is one later file, ten later files (both must retain method_0), and a 320 MiB parent that still rejects the graph while naming the parent admission budget.
  • Base reproduction: before the change, the fixture exited 0 with a partial semantic graph (5 nodes, 2 relations), the admission error above, and worker-memory remediation. Captured locally; not the reporter's Linux cgroup.
  • User-visible CLI output: two runs of analyze-javascript-application --artifact-format directory --json on a-large.mjs plus ten later modules, parent old space 512 MiB, both exited 0 with parsed_javascript_files=11, parse_failures=0, visited_ast_nodes=17672, truncated=false, 12,041 semantic nodes, 8,020 relations, and method_0 retained.
  • Remaining proof gaps: the unattached 439,680-byte and 438,705-byte wrappers were not executed here. The Linux x86_64 one-CPU / 3 GiB process-tree limit was not executed on this macOS arm64 host.

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

  • npm run test:focused -- tests/boundary/cli/javascriptAdmissionBudget.test.ts — 3 tests passed (Node 24.18.0), including ten later sources and the 320 MiB rejection.
  • npm run test:focused -- tests/boundary/javascript/javascriptSourceAnalysisWorker.test.ts — 7 tests passed in the same earlier focused run.
  • npm run check — exit 0.
  • npm run build:cached — exit 0.
  • NODE_OPTIONS=--max-old-space-size=512 node scripts/rea.mjs analyze-javascript-application <fixture> --artifact-format directory --json — exit 0, twice, with the same retained semantic graph.
  • npm run docs:check — not applicable; no generated catalog or docs contract change.
  • Real Hopper/Ghidra/IDA — not applicable.

Compatibility, safety, and release

  • Breaking changes or migration steps: none. Callers that only read parent_result_budget_bytes still receive it. Admission failures add parent_admission_budget_bytes and future_static_reserve_bytes.
  • Real Hopper/Ghidra, browser, or OS coverage: JavaScript CLI/worker only, macOS arm64, Node 24.18.0. Worker old space remained 1024 MiB.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: deferred records stay inside the existing private runtime root and are removed on admission, rejection, or close.

Review checklist

  • This PR addresses a concrete problem or an agreed enhancement.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/1920 **Author:** [@jimpablo](https://github.com/jimpablo) **Created:** 10/11/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/javascript-parent-admission` --- ### 📝 Commits (2) - [`93df06e`](https://github.com/morluto/rea/commit/93df06eacb6ef73b095cf02185830390fc92dd18) fix(javascript): admit deferred semantic graphs after later sources - [`40096c1`](https://github.com/morluto/rea/commit/40096c16a72c94b4fc5bf15f20597032b9e853bc) fix(javascript): reserve only the next static checkpoint ### 📊 Changes **5 files changed** (+365 additions, -64 deletions) <details> <summary>View changed files</summary> 📝 `src/application/javascript/JavaScriptArtifactAnalysis.ts` (+28 -1) 📝 `src/domain/javascript/javascriptSourceAnalysis.ts` (+14 -0) 📝 `src/javascript/analysis/JavaScriptAnalysisTransfer.ts` (+4 -1) 📝 `src/javascript/analysis/JavaScriptAnalysisWorker.ts` (+189 -62) ➕ `tests/boundary/cli/javascriptAdmissionBudget.test.ts` (+130 -0) </details> ### 📄 Description ## Summary Fixes #1911. Fixes #1847. On current main, the original #1847 worker-heap exhaustion no longer reproduces for the two generated wrappers (maintainer check at `898d5096`, and this host did not see `exhausted its heap`). Directory analysis of the reduced two-file fixture from that investigation still drops the earlier file's completed semantic graph: the parent reserves 80% of its result budget whenever any later source remains, then the recovery text tells the caller to raise the worker heap. This change reserves only the next static checkpoint (8 MiB, charged at the existing six-byte retention expansion), not one full checkpoint for every later file. A graph that fits once that reserve shrinks is kept and admitted after the later sources are analyzed. If the parent budget cannot start semantic analysis, the diagnostic names parent admission instead of the worker heap. ## Problem and expected behavior `a-large.mjs` (800 generated functions, objects, and bindings; 86,180 bytes) plus `z-tiny.mjs` (`export const tiny = 1;`) parses with 17,609 AST nodes and zero parse failures. Under `NODE_OPTIONS=--max-old-space-size=512`, the worker heap stays at the default 1,024 MiB and completes, but the parent reports: `Semantic graph for a-large.mjs exceeds the parent's remaining result budget; static and module facts were retained` with `parent_result_budget_bytes=197848196`, `graph_transfer_bytes=17946120`, `graph_records=24007`, and remediation that says to review worker memory. No `method_0` semantic node is returned. After this change the same command keeps syntax evidence and returns the semantic graph (12,005 nodes, 8,002 relations, including `method_0`) without truncation and without a worker-heap failure. ## Change and scope - `#futureStaticReserve` replaces the 80% parent-budget reserve. - Graphs blocked only by that future-static reserve stay on the private runtime and are admitted by `admitDeferredSemanticGraphs` after later sources reduce the reserve. Graphs that still do not fit are rejected with the parent-admission error. - Worker `heapMb` default stays 1024. No MCP catalog, skill, or generated-doc change. ## Contract and boundary impact - Semantic owner and earliest changed stage: parent result admission in `JavaScriptAnalysisWorker`, after the worker checkpoint. - CLI and MCP/tool-catalog contract: none. Same `analyze` / `analyze-javascript-application` result shape; admission failures now include `parent_admission_budget_bytes` and `future_static_reserve_bytes`, and their remediation no longer blames the worker heap. - Provider, bridge, target-format, or platform compatibility: none. - Evidence, artifact, provenance, or reconstruction contract: a semantic graph that was previously omitted is now retained when it fits the resource-derived budget. Observations, unknowns, and syntax facts are unchanged. - Process execution, authorization, cleanup, or containment impact: deferred transfer records stay in the existing private runtime until admission or close. - Generated metadata, package, or installation impact: none. ## Evidence and regression coverage - Tests added or updated: `tests/boundary/cli/javascriptAdmissionBudget.test.ts` runs `rea analyze` through the compiled CLI, which spawns the production JavaScript analysis worker. The parent process is limited with `NODE_OPTIONS=--max-old-space-size`. The tests do not pass `max_heap_mb`, so the worker stays at the default 1024 MiB. Coverage is one later file, ten later files (both must retain `method_0`), and a 320 MiB parent that still rejects the graph while naming the parent admission budget. - Base reproduction: before the change, the fixture exited 0 with a partial semantic graph (5 nodes, 2 relations), the admission error above, and worker-memory remediation. Captured locally; not the reporter's Linux cgroup. - User-visible CLI output: two runs of `analyze-javascript-application --artifact-format directory --json` on `a-large.mjs` plus ten later modules, parent old space 512 MiB, both exited 0 with `parsed_javascript_files=11`, `parse_failures=0`, `visited_ast_nodes=17672`, `truncated=false`, 12,041 semantic nodes, 8,020 relations, and `method_0` retained. - Remaining proof gaps: the unattached 439,680-byte and 438,705-byte wrappers were not executed here. The Linux x86_64 one-CPU / 3 GiB process-tree limit was not executed on this macOS arm64 host. For evidence-bearing changes: - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed - `npm run test:focused -- tests/boundary/cli/javascriptAdmissionBudget.test.ts` — 3 tests passed (Node 24.18.0), including ten later sources and the 320 MiB rejection. - `npm run test:focused -- tests/boundary/javascript/javascriptSourceAnalysisWorker.test.ts` — 7 tests passed in the same earlier focused run. - `npm run check` — exit 0. - `npm run build:cached` — exit 0. - `NODE_OPTIONS=--max-old-space-size=512 node scripts/rea.mjs analyze-javascript-application <fixture> --artifact-format directory --json` — exit 0, twice, with the same retained semantic graph. - `npm run docs:check` — not applicable; no generated catalog or docs contract change. - Real Hopper/Ghidra/IDA — not applicable. ## Compatibility, safety, and release - Breaking changes or migration steps: none. Callers that only read `parent_result_budget_bytes` still receive it. Admission failures add `parent_admission_budget_bytes` and `future_static_reserve_bytes`. - Real Hopper/Ghidra, browser, or OS coverage: JavaScript CLI/worker only, macOS arm64, Node 24.18.0. Worker old space remained 1024 MiB. - Package or release metadata impact: none. - Security, privacy, process, or containment review: deferred records stay inside the existing private runtime root and are removed on admission, rejection, or close. ## Review checklist - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 00:56:40 +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#4910
No description provided.