[PR #1610] [CLOSED] fix(javascript): bound module source payload before deep semantic analysis #3002

Closed
opened 2026-10-17 21:12:47 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1610
Author: @akushonkamen
Created: 10/10/2026
Status: ❌ Closed

Base: main ← Head: fix/1563-js-payload-bound


📝 Commits (2)

  • c37ede0 fix(javascript): bound module source payload before deep semantic analysis
  • 808ded3 fix(javascript): preserve skipped semantic analysis coverage

📊 Changes

11 files changed (+504 additions, -18 deletions)

View changed files

📝 src/application/javascript/JavaScriptArtifactAnalysis.ts (+10 -2)
➕ src/application/javascript/JavaScriptArtifactAnalysisModuleBudget.test.ts (+60 -0)
📝 src/application/javascript/JavaScriptSemanticGraphBuilder.test.ts (+33 -0)
📝 src/application/javascript/JavaScriptSemanticGraphBuilder.ts (+36 -8)
📝 src/application/javascript/JavaScriptSemanticGraphFlowProjection.ts (+50 -1)
📝 src/domain/javascript/javascriptSemanticCoverage.ts (+5 -0)
📝 src/domain/javascript/javascriptSemanticIr.ts (+33 -6)
➕ src/domain/javascript/javascriptSemanticResourceLimits.test.ts (+67 -0)
📝 src/domain/javascript/javascriptSemanticResourceLimits.ts (+17 -0)
📝 src/domain/javascript/javascriptSemanticValueTypes.ts (+2 -1)
➕ tests/acceptance/applications/javascriptModuleBudget.test.ts (+191 -0)

📄 Description

Summary

Deep semantic analysis of one oversized module could expand past the whole host heap and terminate the CLI/MCP process instead of returning a bounded result. Fixes #1563.

Modules above a 2 MiB source-payload budget now skip deep semantics with an explicit failed coverage that carries the named javascript_semantic_module_source_bytes limit and a disclosed limitation. Static analysis, parsing, and every smaller module continue unaffected; coverage stays partial and names the bounding limit, and no semantic absence is claimed for the degraded module.

Problem and expected behavior

The existing semantic resource limits (src/domain/javascript/javascriptSemanticResourceLimits.ts) only bound single primitive values (256 candidates, 1 MiB per byte value); there was no module-payload-level budget. The semantic main path (src/application/javascript/JavaScriptArtifactAnalysis.ts, analyzeArtifactFileSteps → analyzeParsedJavaScriptSemanticsSteps) expanded multi-MiB module sources inside the host heap, so one 4,762,637-byte module (public Claude Code 2.1.296 member chunk-kasbfbhj.js) exhausted a 768 MiB old space and killed the whole process with a fatal OOM before any JSON output. Expected behavior: the process survives, returns partial coverage, and names the limit that bound the result.

Change and scope

  • New SEMANTIC_MODULE_SOURCE_BYTES_LIMIT = 2 MiB payload budget in the JavaScript semantic resource limits.
  • Modules over budget degrade through moduleSourceBudgetJavaScriptSemanticIr() into an explicit failed coverage carrying the named module-source-bytes limit plus a limitation disclosure.
  • Static analysis and all other modules are unaffected; the CLI/MCP process survives; coverage is partial with a named bound.
  • Known cost: on a 2048 MiB heap the affected member previously completed and now deterministically degrades — an intentional trade for a deterministic upper bound.
  • Not included: the general retained-allocation reduction tracked in #1565 and the collector-allocation direction discussed by N0zoM1z0 on the issue; no overlap with this change.

Contract and boundary impact

  • Semantic owner and earliest changed stage: JavaScript semantic analysis (domain limits + IR), application orchestration in JavaScriptArtifactAnalysis steps.
  • CLI and MCP/tool-catalog contract: analyze-javascript-application no longer terminates on oversized members; it exits 0 with partial coverage, the named limit and the limitation.
  • Provider, bridge, target-format, or platform compatibility: none.
  • Evidence, artifact, provenance, or reconstruction contract: the degraded module reports explicit failed coverage with the named limit; its static parse_status stays complete; semantic absence is not claimed.
  • Process execution, authorization, cleanup, or containment impact: no new processes; the process no longer dies by heap OOM.
  • Generated metadata, package, or installation impact: none.

Evidence and regression coverage

  • Tests added or updated: 5 new tests (4 in src/domain/javascript/javascriptSemanticResourceLimits.test.ts, 1 module-budget test in src/application/javascript/JavaScriptArtifactAnalysisModuleBudget.test.ts).
  • Base reproduction: the failing member was statically extracted from the SHA512-verified official registry tarball @anthropic-ai/claude-code-linux-x64@2.1.296 (never executed); chunk-kasbfbhj.js, 4,762,637 bytes, SHA256 64516393b8f06dce5b74140781d43b1df4e743de3e283526a533508ca1c58147. Red was re-verified on current main 11e3fae6 after this branch was rebased.
  • User-visible CLI/MCP output: partial coverage with limits=[{"name":"javascript_semantic_module_source_bytes","value":2097152,"unit":"bytes"}] and limitation "Module source-payload budget exceeded (maximum 2097152 bytes); deep semantic analysis was skipped for this module."
  • Remaining proof gaps: the ticket-specified 2048 MiB red variant exited 0 (65 s) on this machine and did not reproduce the OOM; the local OOM boundary sits between 768 and 2048 MiB, consistent with the issue's own 768-fail/1024-pass data. The exact allocations inside the semantic stage remain attributed only to the stage, per the issue's follow-up notes.

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

  • Red, current main 11e3fae6 (rebased base, dist rebuilt): timeout 300 env NODE_OPTIONS=--max-old-space-size=768 node scripts/rea.mjs analyze-javascript-application /tmp/rea1563/rea-claude-memory-repro --json → exit 134, stderr FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory, 0 bytes of JSON output.
  • Green, this branch (dist rebuilt after rebase): same command at 768 MiB → exit 0 in 6.83 s; coverage.status=partial, limits=[{"name":"javascript_semantic_module_source_bytes","value":2097152,"unit":"bytes"}], the budget limitation disclosed; the failing member's static parse_status=complete. At 2048 MiB → exit 0 in 6.39 s with the same deterministic degradation.
  • npx vitest run --project domain --project services src/domain/javascript src/application/javascript → 1024 passed / 0 failed (59 files), including the 5 new tests. (On the earlier acceptance base the same slice was 1023 passed / 6 failed, with the same 6 failures on clean c1b5ccf0; current main has since fixed those 6.)
  • npx vitest run --project adapters src/artifacts src/javascript → 107 passed / 0 failed.
  • npx tsc --noEmit → pass; npx oxlint → 0 errors (627 pre-existing warnings); npx oxfmt --check → pass; npm run verify:module-boundaries → 1411 files pass; git diff --check → clean.

Compatibility, safety, and release

  • Breaking changes or migration steps: none. Known behavior change: on larger heaps (e.g. 2048 MiB) the oversized member now deterministically degrades to partial coverage instead of completing.
  • Real Hopper/Ghidra, browser, or OS coverage: not applicable — JavaScript-only change; not performed.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: the change removes a whole-process termination path and introduces no new process, privilege, or network behavior.

🤖 Generated with Claude Code


🔄 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/1610 **Author:** [@akushonkamen](https://github.com/akushonkamen) **Created:** 10/10/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/1563-js-payload-bound` --- ### 📝 Commits (2) - [`c37ede0`](https://github.com/morluto/rea/commit/c37ede0aa0f01592eb59d144db54ccc0bf3243f7) fix(javascript): bound module source payload before deep semantic analysis - [`808ded3`](https://github.com/morluto/rea/commit/808ded32c4b18691365ca5fcc54c090621c92c25) fix(javascript): preserve skipped semantic analysis coverage ### 📊 Changes **11 files changed** (+504 additions, -18 deletions) <details> <summary>View changed files</summary> 📝 `src/application/javascript/JavaScriptArtifactAnalysis.ts` (+10 -2) ➕ `src/application/javascript/JavaScriptArtifactAnalysisModuleBudget.test.ts` (+60 -0) 📝 `src/application/javascript/JavaScriptSemanticGraphBuilder.test.ts` (+33 -0) 📝 `src/application/javascript/JavaScriptSemanticGraphBuilder.ts` (+36 -8) 📝 `src/application/javascript/JavaScriptSemanticGraphFlowProjection.ts` (+50 -1) 📝 `src/domain/javascript/javascriptSemanticCoverage.ts` (+5 -0) 📝 `src/domain/javascript/javascriptSemanticIr.ts` (+33 -6) ➕ `src/domain/javascript/javascriptSemanticResourceLimits.test.ts` (+67 -0) 📝 `src/domain/javascript/javascriptSemanticResourceLimits.ts` (+17 -0) 📝 `src/domain/javascript/javascriptSemanticValueTypes.ts` (+2 -1) ➕ `tests/acceptance/applications/javascriptModuleBudget.test.ts` (+191 -0) </details> ### 📄 Description ## Summary Deep semantic analysis of one oversized module could expand past the whole host heap and terminate the CLI/MCP process instead of returning a bounded result. Fixes #1563. Modules above a 2 MiB source-payload budget now skip deep semantics with an explicit failed coverage that carries the named `javascript_semantic_module_source_bytes` limit and a disclosed limitation. Static analysis, parsing, and every smaller module continue unaffected; coverage stays partial and names the bounding limit, and no semantic absence is claimed for the degraded module. ## Problem and expected behavior The existing semantic resource limits (`src/domain/javascript/javascriptSemanticResourceLimits.ts`) only bound single primitive values (256 candidates, 1 MiB per byte value); there was no module-payload-level budget. The semantic main path (`src/application/javascript/JavaScriptArtifactAnalysis.ts`, `analyzeArtifactFileSteps` → `analyzeParsedJavaScriptSemanticsSteps`) expanded multi-MiB module sources inside the host heap, so one 4,762,637-byte module (public Claude Code 2.1.296 member `chunk-kasbfbhj.js`) exhausted a 768 MiB old space and killed the whole process with a fatal OOM before any JSON output. Expected behavior: the process survives, returns partial coverage, and names the limit that bound the result. ## Change and scope - New `SEMANTIC_MODULE_SOURCE_BYTES_LIMIT` = 2 MiB payload budget in the JavaScript semantic resource limits. - Modules over budget degrade through `moduleSourceBudgetJavaScriptSemanticIr()` into an explicit failed coverage carrying the named module-source-bytes limit plus a limitation disclosure. - Static analysis and all other modules are unaffected; the CLI/MCP process survives; coverage is partial with a named bound. - Known cost: on a 2048 MiB heap the affected member previously completed and now deterministically degrades — an intentional trade for a deterministic upper bound. - Not included: the general retained-allocation reduction tracked in #1565 and the collector-allocation direction discussed by N0zoM1z0 on the issue; no overlap with this change. ## Contract and boundary impact - Semantic owner and earliest changed stage: JavaScript semantic analysis (domain limits + IR), application orchestration in `JavaScriptArtifactAnalysis` steps. - CLI and MCP/tool-catalog contract: `analyze-javascript-application` no longer terminates on oversized members; it exits 0 with partial coverage, the named limit and the limitation. - Provider, bridge, target-format, or platform compatibility: none. - Evidence, artifact, provenance, or reconstruction contract: the degraded module reports explicit failed coverage with the named limit; its static `parse_status` stays `complete`; semantic absence is not claimed. - Process execution, authorization, cleanup, or containment impact: no new processes; the process no longer dies by heap OOM. - Generated metadata, package, or installation impact: none. ## Evidence and regression coverage - Tests added or updated: 5 new tests (4 in `src/domain/javascript/javascriptSemanticResourceLimits.test.ts`, 1 module-budget test in `src/application/javascript/JavaScriptArtifactAnalysisModuleBudget.test.ts`). - Base reproduction: the failing member was statically extracted from the SHA512-verified official registry tarball `@anthropic-ai/claude-code-linux-x64@2.1.296` (never executed); `chunk-kasbfbhj.js`, 4,762,637 bytes, SHA256 `64516393b8f06dce5b74140781d43b1df4e743de3e283526a533508ca1c58147`. Red was re-verified on current main `11e3fae6` after this branch was rebased. - User-visible CLI/MCP output: partial coverage with `limits=[{"name":"javascript_semantic_module_source_bytes","value":2097152,"unit":"bytes"}]` and limitation "Module source-payload budget exceeded (maximum 2097152 bytes); deep semantic analysis was skipped for this module." - Remaining proof gaps: the ticket-specified 2048 MiB red variant exited 0 (65 s) on this machine and did not reproduce the OOM; the local OOM boundary sits between 768 and 2048 MiB, consistent with the issue's own 768-fail/1024-pass data. The exact allocations inside the semantic stage remain attributed only to the stage, per the issue's follow-up notes. 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 - Red, current main `11e3fae6` (rebased base, dist rebuilt): `timeout 300 env NODE_OPTIONS=--max-old-space-size=768 node scripts/rea.mjs analyze-javascript-application /tmp/rea1563/rea-claude-memory-repro --json` → exit 134, stderr `FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory`, 0 bytes of JSON output. - Green, this branch (dist rebuilt after rebase): same command at 768 MiB → exit 0 in 6.83 s; `coverage.status=partial`, `limits=[{"name":"javascript_semantic_module_source_bytes","value":2097152,"unit":"bytes"}]`, the budget limitation disclosed; the failing member's static `parse_status=complete`. At 2048 MiB → exit 0 in 6.39 s with the same deterministic degradation. - `npx vitest run --project domain --project services src/domain/javascript src/application/javascript` → 1024 passed / 0 failed (59 files), including the 5 new tests. (On the earlier acceptance base the same slice was 1023 passed / 6 failed, with the same 6 failures on clean `c1b5ccf0`; current main has since fixed those 6.) - `npx vitest run --project adapters src/artifacts src/javascript` → 107 passed / 0 failed. - `npx tsc --noEmit` → pass; `npx oxlint` → 0 errors (627 pre-existing warnings); `npx oxfmt --check` → pass; `npm run verify:module-boundaries` → 1411 files pass; `git diff --check` → clean. ## Compatibility, safety, and release - Breaking changes or migration steps: none. Known behavior change: on larger heaps (e.g. 2048 MiB) the oversized member now deterministically degrades to partial coverage instead of completing. - Real Hopper/Ghidra, browser, or OS coverage: not applicable — JavaScript-only change; not performed. - Package or release metadata impact: none. - Security, privacy, process, or containment review: the change removes a whole-process termination path and introduces no new process, privilege, or network behavior. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-17 21:12:47 +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#3002
No description provided.