[PR #1871] [MERGED] perf(javascript): skip nested callables during fingerprint traversal #4867

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

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1871
Author: @cyanseek
Created: 10/11/2026
Status: ✅ Merged
Merged: 10/11/2026
Merged by: @morluto

Base: main ← Head: codex/skip-nested-fingerprint-traversal


📝 Commits (1)

  • bcf3819 perf(javascript): skip nested callables during fingerprint traversal

📊 Changes

4 files changed (+63 additions, -12 deletions)

View changed files

📝 src/domain/javascript/javascriptSemanticAnalysis.calls.test.ts (+28 -0)
📝 src/domain/javascript/javascriptSemanticAnalysisSteps.test.ts (+29 -0)
📝 src/domain/javascript/javascriptSemanticFingerprints.ts (+2 -11)
📝 src/domain/javascript/javascriptSemanticTraversal.ts (+4 -1)

📄 Description

Summary

Skip nested callable subtrees while collecting a function's syntax fingerprint. Related to #1065 and the cooperative traversal introduced in #1545.

Problem and expected behavior

fingerprintSyntaxSteps walks each callable's complete subtree, then ignores nodes belonging to nested callables. A deeply nested function body is therefore visited once for every enclosing function even though it contributes tokens only to its own fingerprint. Fingerprint collection should visit the syntax owned by the current callable while preserving every existing fingerprint.

Change and scope

Add an optional child-subtree skip predicate to the shared AST traversal. Fingerprints use it at nested callable boundaries, replacing the local callable stack. The root is still visited; skipped children receive neither enter nor exit callbacks. Traversal order, ancestor snapshots, and cooperative checks remain intact. Each nested callable still gets its own fingerprint in the existing outer collection loop.

Contract and boundary impact

  • Semantic owner: domain JavaScript function fingerprint collection.
  • CLI/MCP and tool catalog: unchanged contracts and complete output.
  • Provider/platform compatibility: shared static JavaScript analysis; no provider changes.
  • Evidence/provenance/reconstruction: unchanged IDs, fingerprint components, source locations, coverage, and unknowns.
  • Process/authorization/cleanup: no change.
  • Generated metadata/package/installation: no change.

Evidence and regression coverage

  • Added behavior tests for skipped-subtree sibling ancestry/exit callbacks and fingerprint ownership across nested functions, object methods, class methods, and subsequent outer statements.
  • Five alternating baseline/candidate pairs on native Windows, Node 24.18.0, Ryzen 7 9700X, with a 1,536 MiB Node heap limit. A generated 400-level nested-function input (27,952 bytes) reduced median semantic analysis from 297.65 to 113.61 ms. Complete CLI process wall time, including full output, changed from 2,536.80 to 2,332.95 ms; median within-pair reduction was 191.94 ms. These are measurements of this generated stress input.
  • Complete serialized IR, normalized results, Evidence IDs, and complete Evidence hashes matched across all ten runs of each of four inputs: generated 160/400-level nesting, the complete @babel/parser@8.0.4 lib/index.js, and the complete lossless-json@4.3.1 UMD file. The published-package sources provide semantic parity coverage.
  • Actual Windows stdio MCP preserved the same complete Evidence as CLI: the smaller inputs passed inline text/structured parity; the 400-level input retained its existing typed transport constraint and successfully exported the complete record. Subsequent ping and analysis passed, and clients/transports were closed.
  • Performance comparison base: 069308b; final patch integrated with d3e9ee5, followed by static, domain, focused, and MCP parity verification.
Generated input
const depth = 400;
const source = Array.from({ length: depth }, (_, i) =>
  `function wrap${i}(value) { const tag${i} = ${i};`
).join('\n') + '\nreturn value;\n' +
Array.from({ length: depth - 1 }, (_, i) =>
  `} return wrap${depth - i - 1}(value);`
).join('\n') + '\n}';

Save as the only main.js in an input directory. Run rea analyze-javascript-application <directory> --artifact-format directory --format json with stdout fully consumed. Semantic timing calls analyzeJavaScriptSemantics(source) separately, excluding result serialization.

  • 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 check — passed, including typecheck, lint/module boundaries, formatting, Knip, metadata, and architecture guards.
  • npm run build:cached — passed.
  • node node_modules/vitest/vitest.mjs run --project domain src/domain/javascript --maxWorkers=2 — 844 passed across 44 files.
  • npm run test:focused -- the two changed test files, javascriptApplicationCancellation.test.ts, javascriptAnalysisCancellation.test.ts, javascriptCancellationCli.test.ts, and packageSubpathsCli.test.ts — 34 passed; two POSIX SIGINT cases use the suite's existing Windows skip. SDK cancellation/recovery and native Windows CLI/MCP cases passed.
  • Complete CLI/stdio MCP comparisons described above — passed.
  • git diff --check and commit hooks — passed.

Compatibility, safety, and release

No breaking change, migration, or package metadata change. Verification covers native Windows static JavaScript workflows. Hopper/Ghidra/browser execution is outside this change; no new engine or runtime-execution capability is claimed.

Review checklist

  • Concrete problem, focused outcome, and Conventional Commit title.
  • Related work linked; this does not close the broader #1065 roadmap.
  • Tests cover ownership, traversal behavior, and existing cancellation/recovery boundaries.
  • Existing contracts and generated metadata remain unchanged.
  • Final diff checked for secrets, unrelated changes, 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/1871 **Author:** [@cyanseek](https://github.com/cyanseek) **Created:** 10/11/2026 **Status:** ✅ Merged **Merged:** 10/11/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `codex/skip-nested-fingerprint-traversal` --- ### 📝 Commits (1) - [`bcf3819`](https://github.com/morluto/rea/commit/bcf38193c6e07eeec2b39424a03b832541ba390d) perf(javascript): skip nested callables during fingerprint traversal ### 📊 Changes **4 files changed** (+63 additions, -12 deletions) <details> <summary>View changed files</summary> 📝 `src/domain/javascript/javascriptSemanticAnalysis.calls.test.ts` (+28 -0) 📝 `src/domain/javascript/javascriptSemanticAnalysisSteps.test.ts` (+29 -0) 📝 `src/domain/javascript/javascriptSemanticFingerprints.ts` (+2 -11) 📝 `src/domain/javascript/javascriptSemanticTraversal.ts` (+4 -1) </details> ### 📄 Description ## Summary Skip nested callable subtrees while collecting a function's syntax fingerprint. Related to #1065 and the cooperative traversal introduced in #1545. ## Problem and expected behavior `fingerprintSyntaxSteps` walks each callable's complete subtree, then ignores nodes belonging to nested callables. A deeply nested function body is therefore visited once for every enclosing function even though it contributes tokens only to its own fingerprint. Fingerprint collection should visit the syntax owned by the current callable while preserving every existing fingerprint. ## Change and scope Add an optional child-subtree `skip` predicate to the shared AST traversal. Fingerprints use it at nested callable boundaries, replacing the local callable stack. The root is still visited; skipped children receive neither enter nor exit callbacks. Traversal order, ancestor snapshots, and cooperative checks remain intact. Each nested callable still gets its own fingerprint in the existing outer collection loop. ## Contract and boundary impact - Semantic owner: domain JavaScript function fingerprint collection. - CLI/MCP and tool catalog: unchanged contracts and complete output. - Provider/platform compatibility: shared static JavaScript analysis; no provider changes. - Evidence/provenance/reconstruction: unchanged IDs, fingerprint components, source locations, coverage, and unknowns. - Process/authorization/cleanup: no change. - Generated metadata/package/installation: no change. ## Evidence and regression coverage - Added behavior tests for skipped-subtree sibling ancestry/exit callbacks and fingerprint ownership across nested functions, object methods, class methods, and subsequent outer statements. - Five alternating baseline/candidate pairs on native Windows, Node 24.18.0, Ryzen 7 9700X, with a 1,536 MiB Node heap limit. A **generated 400-level nested-function input** (27,952 bytes) reduced median semantic analysis from **297.65 to 113.61 ms**. Complete CLI process wall time, including full output, changed from **2,536.80 to 2,332.95 ms**; median within-pair reduction was **191.94 ms**. These are measurements of this generated stress input. - Complete serialized IR, normalized results, Evidence IDs, and complete Evidence hashes matched across all ten runs of each of four inputs: generated 160/400-level nesting, the complete `@babel/parser@8.0.4` `lib/index.js`, and the complete `lossless-json@4.3.1` UMD file. The published-package sources provide semantic parity coverage. - Actual Windows stdio MCP preserved the same complete Evidence as CLI: the smaller inputs passed inline text/structured parity; the 400-level input retained its existing typed transport constraint and successfully exported the complete record. Subsequent ping and analysis passed, and clients/transports were closed. - Performance comparison base: `069308b`; final patch integrated with `d3e9ee5`, followed by static, domain, focused, and MCP parity verification. <details> <summary>Generated input</summary> ```js const depth = 400; const source = Array.from({ length: depth }, (_, i) => `function wrap${i}(value) { const tag${i} = ${i};` ).join('\n') + '\nreturn value;\n' + Array.from({ length: depth - 1 }, (_, i) => `} return wrap${depth - i - 1}(value);` ).join('\n') + '\n}'; ``` Save as the only `main.js` in an input directory. Run `rea analyze-javascript-application <directory> --artifact-format directory --format json` with stdout fully consumed. Semantic timing calls `analyzeJavaScriptSemantics(source)` separately, excluding result serialization. </details> - [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 check` — passed, including typecheck, lint/module boundaries, formatting, Knip, metadata, and architecture guards. - `npm run build:cached` — passed. - `node node_modules/vitest/vitest.mjs run --project domain src/domain/javascript --maxWorkers=2` — 844 passed across 44 files. - `npm run test:focused --` the two changed test files, `javascriptApplicationCancellation.test.ts`, `javascriptAnalysisCancellation.test.ts`, `javascriptCancellationCli.test.ts`, and `packageSubpathsCli.test.ts` — 34 passed; two POSIX SIGINT cases use the suite's existing Windows skip. SDK cancellation/recovery and native Windows CLI/MCP cases passed. - Complete CLI/stdio MCP comparisons described above — passed. - `git diff --check` and commit hooks — passed. ## Compatibility, safety, and release No breaking change, migration, or package metadata change. Verification covers native Windows static JavaScript workflows. Hopper/Ghidra/browser execution is outside this change; no new engine or runtime-execution capability is claimed. ## Review checklist - [x] Concrete problem, focused outcome, and Conventional Commit title. - [x] Related work linked; this does not close the broader #1065 roadmap. - [x] Tests cover ownership, traversal behavior, and existing cancellation/recovery boundaries. - [x] Existing contracts and generated metadata remain unchanged. - [x] Final diff checked for secrets, unrelated changes, 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:12 +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#4867
No description provided.