[PR #6360] [MERGED] fix(javascript): report path data records as route candidates #7306

Closed
opened 2026-11-01 21:46:55 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/6360
Author: @Nikhi00718
Created: 10/22/2026
Status: ✅ Merged
Merged: 10/22/2026
Merged by: @morluto

Base: main ← Head: fix/javascript-route-property-confidence


📝 Commits (2)

  • 5f2a3e8 fix(javascript): report path data records as route candidates
  • 1e31386 fix(javascript): scan each route record's keys once

📊 Changes

5 files changed (+177 additions, -35 deletions)

View changed files

📝 src/application/javascript/JavaScriptArtifactGraphFindings.ts (+3 -1)
📝 src/domain/javascript/javascriptRouteScan.ts (+60 -21)
📝 src/domain/javascript/javascriptStaticAnalysis.routeProperties.test.ts (+63 -12)
📝 src/domain/javascript/javascriptStaticAnalysisTypes.ts (+4 -1)
📝 tests/boundary/filesystem/javascript-applications/javascriptArtifactGraphEndpoints.test.ts (+47 -0)

📄 Description

Summary

Fixes #6349.

analyze_javascript_application reported every string path/route object property as an exact, observed route endpoint, whatever object held it. Data records such as { type: "set", path: "updatedAt", value: 1 } therefore became exact routes, while a real app.get("/real-route", ...) in the same file was only a low-confidence network candidate. On the npm package @agentmemory/agentmemory@0.9.30 this gave 13 exact routes, none of them real.

Problem and expected behavior

Smallest trigger:

const patch = [{ type: "set", path: "updatedAt", value: 1 }];
const worktree = { path: "", head: "" };

Before: two route endpoints, mechanism: "property:path", no interpretation, projected as discover-static-endpoint / ast-static-analysis / observed / exact.

Violated invariant: an observed, exact finding should be backed by syntax that establishes it. A property name alone does not establish a route.

After: both are kept, but as interpretation: "candidate", projected as classify-static-endpoint-candidate / static-relationship-inference / inferred / low, with the limitation "Only the property name suggests a route; the enclosing object has no router fields." Router records such as { path: "settings", component: Settings } stay exact.

Change and scope

  • javascriptRouteScan.ts: the key scan in #object moves into a routeRecordShape helper with no change in behavior, cached once per object (#shape) so repeated path/route keys do not rescan the object. #property now receives its parent, and marks the legacy property:path / property:route finding as a candidate unless the parent is a router record: component, element, Component, children, or a typed _$ record. That is the same shape #object already uses to choose automatic route roots, so route recognition has one rule instead of two.
  • JavaScriptArtifactGraphFindings.ts: route candidates get a route-specific limitation. The existing network-candidate text talks about method receivers, which does not apply here.
  • javascriptStaticAnalysisTypes.ts: the interpretation doc comment now covers both kinds of candidate.

Not included:

  • analyze_web_bundle uses the same route scan, but its route finding schema (value, mechanism, location) has no confidence field. Its legacy route list is unchanged. Adding a field there changes a public output contract and should be a separate decision.
  • Router records that only have Angular/Vue/React Router keys outside this set (redirectTo, loadChildren, loadComponent, redirect, lazy) are now candidates rather than exact. They are still reported. Widening the shared shape would also change which objects #object treats as automatic route roots, so I left that alone.

Contribution scope: an ordinary fix inside the existing static JavaScript analysis boundary; maintainer scope decision not applicable. #6349 asked which of two contracts to use. This PR implements option 1 (demote by shape), because it removes no findings. Happy to switch to option 2 (drop non-router properties) if you prefer.

Contract and boundary impact

  • Semantic owner and earliest changed stage: JavaScriptRouteScan in src/domain/javascript, during static analysis.
  • Contribution scope fit and linked maintainer decision: in scope (static analysis fix); option choice asked in #6349.
  • CLI and MCP/tool-catalog contract: no schema change. Some route endpoints gain interpretation: "candidate" and are projected with candidate evidence, an existing shape already used for network candidates.
  • Provider, bridge, target-format, or platform compatibility: none.
  • Evidence, artifact, provenance, or reconstruction contract: affected route endpoints move from observed/exact to inferred/low; endpoint identity keys include the interpretation, so their node ids change.
  • Target selection, authority, upstream behavior, and cleanup details: not applicable.
  • Generated metadata, package, or installation impact: none.

Expected effects (check known effects; use documentation-only on its own).
Unchecked items do not establish absence; leave uncertainties visible.

  • Read existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

  • Tests added or updated:
    • src/domain/javascript/javascriptStaticAnalysis.routeProperties.test.ts: the existing case now uses router records (component/element) and still expects exact results. New cases cover children and typed _$ records staying exact, and patch ops, a { path, head } record and a bare { path: "/bare" } becoming candidates. A timed case checks that one object with 20,000 path keys stays under 2 s.
    • tests/boundary/filesystem/javascript-applications/javascriptArtifactGraphEndpoints.test.ts: the graph projection gives a patch-op path inferred/low evidence with the route limitation, while a router record in the same file stays observed/exact.
  • Base reproduction: on fd5cd1b with the javascriptRouteScan.ts change stashed, the new candidate test fails (× reports path properties outside router records only as candidates); with the change it passes. The original report reproduced on rea-agents@6.7.0 (MCP) and 54f51f0 (#6349).
  • User-visible output: for the #6349 fixture, analyzeJavaScriptStaticSource(...).endpoints now returns updatedAt and "" with interpretation: "candidate"; /real-route is unchanged.
  • Remaining proof gaps: not re-run through the built CLI/MCP. Acceptance tests that start scripts/rea.mjs were not run (no build in this checkout). Real-world effect measured only on the #6349 fixture and the agentmemory bundle.

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

  • npx vitest run src/domain/javascript/javascriptStaticAnalysis.routeProperties.test.ts — 4 passed (repeated-keys case 564 ms).
  • Same file on 5f2a3e8 (before the per-object cache) — repeated-keys case failed at 82,255 ms.
  • Same file with the javascriptRouteScan.ts change stashed — 1 failed (the new candidate case), 2 passed.
  • npx vitest run tests/boundary/filesystem/javascript-applications/javascriptArtifactGraphEndpoints.test.ts — 3 passed.
  • npx vitest run src/domain/javascript src/application/javascript src/domain/webBundle tests/boundary/filesystem/javascript-applications, compared with the same run on base fd5cd1b — before: 4546 tests, 168 failed; after (1e31386): 4550 tests, 168 failed; no test changed from pass to fail. The 168 failures happen on base too: this Windows source checkout has no native addon ("REA Windows native controls are unavailable", see CONTRIBUTING "Windows source checkouts"), plus 4 ENOENT and 1 cancellation case in the same files.
  • npm run check:fast (typecheck, lint) — 2 tasks successful.
  • npx oxfmt --check on the changed files — correct format.

Compatibility, safety, and release

  • Breaking changes or migration steps: none in schema. Callers that treated every property:path route as exact will now see some of them as candidates with inferred/low evidence, and those endpoints get new node ids.
  • Real Hopper/Ghidra, browser, or OS coverage: not applicable; Windows 11, Node v24.15.0.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: no new reads, execution, or network access.

Author readiness

Human owner: @Nikhi00718

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • 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/6360 **Author:** [@Nikhi00718](https://github.com/Nikhi00718) **Created:** 10/22/2026 **Status:** ✅ Merged **Merged:** 10/22/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `fix/javascript-route-property-confidence` --- ### 📝 Commits (2) - [`5f2a3e8`](https://github.com/morluto/rea/commit/5f2a3e89cf23583ebf85b3546ae49f44db633c42) fix(javascript): report path data records as route candidates - [`1e31386`](https://github.com/morluto/rea/commit/1e31386e12bb42fe6c08896cf72f1c69a2ba8f05) fix(javascript): scan each route record's keys once ### 📊 Changes **5 files changed** (+177 additions, -35 deletions) <details> <summary>View changed files</summary> 📝 `src/application/javascript/JavaScriptArtifactGraphFindings.ts` (+3 -1) 📝 `src/domain/javascript/javascriptRouteScan.ts` (+60 -21) 📝 `src/domain/javascript/javascriptStaticAnalysis.routeProperties.test.ts` (+63 -12) 📝 `src/domain/javascript/javascriptStaticAnalysisTypes.ts` (+4 -1) 📝 `tests/boundary/filesystem/javascript-applications/javascriptArtifactGraphEndpoints.test.ts` (+47 -0) </details> ### 📄 Description ## Summary Fixes #6349. `analyze_javascript_application` reported every string `path`/`route` object property as an exact, observed `route` endpoint, whatever object held it. Data records such as `{ type: "set", path: "updatedAt", value: 1 }` therefore became exact routes, while a real `app.get("/real-route", ...)` in the same file was only a low-confidence `network` candidate. On the npm package `@agentmemory/agentmemory@0.9.30` this gave 13 exact routes, none of them real. ## Problem and expected behavior Smallest trigger: ```js const patch = [{ type: "set", path: "updatedAt", value: 1 }]; const worktree = { path: "", head: "" }; ``` Before: two `route` endpoints, `mechanism: "property:path"`, no `interpretation`, projected as `discover-static-endpoint` / `ast-static-analysis` / `observed` / `exact`. Violated invariant: an observed, exact finding should be backed by syntax that establishes it. A property name alone does not establish a route. After: both are kept, but as `interpretation: "candidate"`, projected as `classify-static-endpoint-candidate` / `static-relationship-inference` / `inferred` / `low`, with the limitation "Only the property name suggests a route; the enclosing object has no router fields." Router records such as `{ path: "settings", component: Settings }` stay exact. ## Change and scope - `javascriptRouteScan.ts`: the key scan in `#object` moves into a `routeRecordShape` helper with no change in behavior, cached once per object (`#shape`) so repeated `path`/`route` keys do not rescan the object. `#property` now receives its parent, and marks the legacy `property:path` / `property:route` finding as a candidate unless the parent is a router record: `component`, `element`, `Component`, `children`, or a typed `_$` record. That is the same shape `#object` already uses to choose automatic route roots, so route recognition has one rule instead of two. - `JavaScriptArtifactGraphFindings.ts`: route candidates get a route-specific limitation. The existing network-candidate text talks about method receivers, which does not apply here. - `javascriptStaticAnalysisTypes.ts`: the `interpretation` doc comment now covers both kinds of candidate. Not included: - `analyze_web_bundle` uses the same route scan, but its route finding schema (`value`, `mechanism`, `location`) has no confidence field. Its legacy route list is unchanged. Adding a field there changes a public output contract and should be a separate decision. - Router records that only have Angular/Vue/React Router keys outside this set (`redirectTo`, `loadChildren`, `loadComponent`, `redirect`, `lazy`) are now candidates rather than exact. They are still reported. Widening the shared shape would also change which objects `#object` treats as automatic route roots, so I left that alone. Contribution scope: an ordinary fix inside the existing static JavaScript analysis boundary; maintainer scope decision not applicable. #6349 asked which of two contracts to use. This PR implements option 1 (demote by shape), because it removes no findings. Happy to switch to option 2 (drop non-router properties) if you prefer. ## Contract and boundary impact - Semantic owner and earliest changed stage: `JavaScriptRouteScan` in `src/domain/javascript`, during static analysis. - Contribution scope fit and linked maintainer decision: in scope (static analysis fix); option choice asked in #6349. - CLI and MCP/tool-catalog contract: no schema change. Some `route` endpoints gain `interpretation: "candidate"` and are projected with candidate evidence, an existing shape already used for network candidates. - Provider, bridge, target-format, or platform compatibility: none. - Evidence, artifact, provenance, or reconstruction contract: affected route endpoints move from observed/exact to inferred/low; endpoint identity keys include the interpretation, so their node ids change. - Target selection, authority, upstream behavior, and cleanup details: not applicable. - Generated metadata, package, or installation impact: none. Expected effects (check known effects; use documentation-only on its own). Unchecked items do not establish absence; leave uncertainties visible. - [x] Read existing files or captured data. - [ ] Launch or attach to a process. - [ ] Inject instrumentation or run scripts/code. - [ ] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. ## Evidence and regression coverage - Tests added or updated: - `src/domain/javascript/javascriptStaticAnalysis.routeProperties.test.ts`: the existing case now uses router records (`component`/`element`) and still expects exact results. New cases cover `children` and typed `_$` records staying exact, and patch ops, a `{ path, head }` record and a bare `{ path: "/bare" }` becoming candidates. A timed case checks that one object with 20,000 `path` keys stays under 2 s. - `tests/boundary/filesystem/javascript-applications/javascriptArtifactGraphEndpoints.test.ts`: the graph projection gives a patch-op `path` inferred/low evidence with the route limitation, while a router record in the same file stays observed/exact. - Base reproduction: on `fd5cd1b` with the `javascriptRouteScan.ts` change stashed, the new candidate test fails (`× reports path properties outside router records only as candidates`); with the change it passes. The original report reproduced on `rea-agents@6.7.0` (MCP) and `54f51f0` (#6349). - User-visible output: for the #6349 fixture, `analyzeJavaScriptStaticSource(...).endpoints` now returns `updatedAt` and `""` with `interpretation: "candidate"`; `/real-route` is unchanged. - Remaining proof gaps: not re-run through the built CLI/MCP. Acceptance tests that start `scripts/rea.mjs` were not run (no build in this checkout). Real-world effect measured only on the #6349 fixture and the agentmemory bundle. 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 - `npx vitest run src/domain/javascript/javascriptStaticAnalysis.routeProperties.test.ts` — 4 passed (repeated-keys case 564 ms). - Same file on 5f2a3e8 (before the per-object cache) — repeated-keys case failed at 82,255 ms. - Same file with the `javascriptRouteScan.ts` change stashed — 1 failed (the new candidate case), 2 passed. - `npx vitest run tests/boundary/filesystem/javascript-applications/javascriptArtifactGraphEndpoints.test.ts` — 3 passed. - `npx vitest run src/domain/javascript src/application/javascript src/domain/webBundle tests/boundary/filesystem/javascript-applications`, compared with the same run on base `fd5cd1b` — before: 4546 tests, 168 failed; after (1e31386): 4550 tests, 168 failed; no test changed from pass to fail. The 168 failures happen on base too: this Windows source checkout has no native addon ("REA Windows native controls are unavailable", see CONTRIBUTING "Windows source checkouts"), plus 4 ENOENT and 1 cancellation case in the same files. - `npm run check:fast` (typecheck, lint) — 2 tasks successful. - `npx oxfmt --check` on the changed files — correct format. ## Compatibility, safety, and release - Breaking changes or migration steps: none in schema. Callers that treated every `property:path` route as exact will now see some of them as candidates with inferred/low evidence, and those endpoints get new node ids. - Real Hopper/Ghidra, browser, or OS coverage: not applicable; Windows 11, Node v24.15.0. - Package or release metadata impact: none. - Security, privacy, process, or containment review: no new reads, execution, or network access. ## Author readiness Human owner: @Nikhi00718 - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge - [ ] This PR addresses a concrete problem or an agreed enhancement. - [ ] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [ ] 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. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-11-01 21:46:55 +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#7306
No description provided.