Skip to content

Implement PR-A2: SpEL/constant-ref routes and route MCP tools#7

Merged
HumanBean17 merged 1 commit into
masterfrom
cursor/b2a-spel-mcp
May 4, 2026
Merged

Implement PR-A2: SpEL/constant-ref routes and route MCP tools#7
HumanBean17 merged 1 commit into
masterfrom
cursor/b2a-spel-mcp

Conversation

@HumanBean17

Copy link
Copy Markdown
Owner

Summary

Implements PR-A2 from plans/PLAN-TIER1-COMPLETION.md / plans/CURSOR-PROMPTS-TIER1.md (B2a SpEL/constant-ref + read-only route tools).

Behaviour

  • ast_java.py: three-strategy route values (literal → annotation, string with ${…}spel, other AST → constant_ref) for HTTP mappings and messaging annotations; merge with class-level path preserves constant_ref for concat expressions that are not a single string literal.
  • build_ast_graph.py: unresolved HTTP routes get empty path_template / path_regex; _route_id includes raw path when template is empty to avoid id collisions.
  • kuzu_queries.py: list_routes, find_route_handlers, get_route_by_path.
  • server.py: MCP tools + _INSTRUCTIONS (notes find_route_callers deferred to B2b).
  • Tests: route extraction 8–9 updated, 12–14 added; Kuzu 15–17 on route_extraction_smoke; MCP smoke; FeignTripleDup fixture for three handlers on one route id.
  • README.md: tools table + short route-resolution note.

Validation

  • python3 -m pytest tests -q177 passed, 3 skipped.

Manual / fixture note

  • Rebuild on tests/bank-chat-system: routes_resolved_pct was ~81.8% in a local pass4 run (mix of resolved and unresolved routes).

Re-index

  • Users with an existing Kuzu graph should rebuild (build_ast_graph.py or refresh_code_index) to pick up route semantics; ontology version unchanged at 5.

Made with Cursor

@HumanBean17

Copy link
Copy Markdown
Owner Author

Review: PR-A2 — SpEL/constant-ref routes + Route MCP tools

Verdict: Approved ✅

Clean, surgical implementation that finishes B2a per plan. Three-strategy ladder, kuzu helpers, and MCP wiring all match the proposal; scope discipline is excellent (zero leak into B2b/A3/brownfield/schema/ontology).

Scope discipline (out-of-scope checks)

Area Expected Result
HTTP_CALLS / ASYNC_CALLS edges (B2b/B6) untouched ✅ none introduced
find_route_callers impl deferred ✅ only mentioned in docstring + _INSTRUCTIONS line 55
Brownfield overrides untouched ✅ no changes
Ontology version stays at 5 (bumped in PR-A1) ✅ no bump
Route schema unchanged ✅ no new columns
_normalize_path reused as-is ✅ pure reuse

Three-strategy ladder

ast_java.py route extraction now returns tuple[str, str, float, bool] (path, strategy, confidence, resolved) flowing through every emission site. Confidences match the locked plan (literal=1.0, SpEL=0.85, constant_ref=0.7).

The new _merge_http_route_with_class_base helper handles class+method composition correctly, including the subtle edge case where ${…} inside a non-string-literal stays constant_ref (not promoted to SpEL). Stickiness is right — string concat with a constant ref → constant_ref, never accidentally upgraded.

_route_id path_raw parameter — nice catch

Adding path_raw as a positional disambiguator prevents id collision when SpEL/const routes share an empty path_template. Backward compat is maintained via the PR-A1 test 11 update (still green). Comment in code explains intent clearly.

routes_skipped_unresolved semantics

Correctly narrowed — now only counts AST-level non-extractable cases (topicPattern, bindings). SpEL/constant_ref are emitted as unresolved Route nodes instead of dropped. Cases 8 & 9 were updated accordingly (previously asserted "skipped", now assert "emitted as unresolved") — correct migration.

Kuzu helpers (kuzu_queries.py)

  • list_routes — sensible Cypher, all four filters (microservice / framework / path_prefix / method) AND-combined, limit clamped 1–500.
  • find_route_handlers — returns list (correct for Feign arrays + class-level @RequestMapping arrays); includes confidence + strategy per handler.
  • get_route_by_path — filters on path_template (the normalized form) which is consistent with what list_routes returns; microservice-scoped.

MCP tool wiring (server.py:933, 961, 985)

All three tools use asyncio.to_thread for sync graph calls, Pydantic Field validation, and proper DTO mapping (_route_dict_to_dto, RouteHandlerEntryDto). Tool descriptions correctly warn that SpEL-only routes have empty path_template and steer users to path_prefix for those. _INSTRUCTIONS updates (lines 53–55) are honest about deferred caller edges.

Tests

177 passed, 3 skipped

+7 new vs PR-A1 baseline (170). All planned tests landed:

  • test_route_extraction.py::test_case12_get_mapping_spel_path — SpEL path
  • test_case13_get_mapping_constant_ref — constant ref
  • test_case14_request_mapping_string_concat_is_constant_ref — concat stickiness
  • test_kuzu_queries.py::test_list_routes_filter_by_framework
  • test_find_route_handlers_feign_array — uses new FeignTripleDup.java fixture
  • test_get_route_by_path_microservice_isolated

Manual evidence reproduced

Ran python build_ast_graph.py --source-root tests/bank-chat-system --kuzu-path /tmp/check_kuzu_a2 --verbose:

[pass4] Route extraction: emitted=11, exposes=11, skipped_unresolved=0,
        routes_resolved_pct=81.8, by_framework={'spring_mvc': 9, 'kafka': 2}

✅ Matches your claim exactly.

Minor observations (non-blocking)

  1. find_route_handlers returns plural by design — please ensure the B2b prompt expects an array when wiring (caller)-[:HTTP_CALLS]->(Route)<-[:EXPOSES]-(handler) traversal (multiple handlers per Route id is the common case for class-level mappings).
  2. get_route_by_path requires microservice (no global lookup) — correct for multi-repo monorepos but worth noting in B2b prompt if a caller search needs to fall back across services.
  3. _INSTRUCTIONS is getting long — fine for now, but consider sectioning by capability if you add 2–3 more tools in B2b.

Plan deltas needed

None. This PR matches PLAN-TIER1-COMPLETION.md §B2a precisely. Ready to merge.


Next up: PR-A3 (path-template registry + microservice scoping for routes) per the plan, then PR-A4/A5 (B2b: HTTP_CALLS edges + find_route_callers).

@HumanBean17 HumanBean17 merged commit a2d46d5 into master May 4, 2026
@HumanBean17 HumanBean17 deleted the cursor/b2a-spel-mcp branch May 5, 2026 07:31
HumanBean17 added a commit that referenced this pull request May 23, 2026
HumanBean17 added a commit that referenced this pull request May 23, 2026
…gns (#213)

* plan: DESCRIBE-HINTS-STRUCTURAL — type wiring and method-body road signs

Co-Authored-By: Claude Opus 4.7 <[email protected]>

* plan: remove optional label from test #7 (21 tests, all required)

Co-Authored-By: Claude Opus 4.7 <[email protected]>

---------

Co-authored-by: Claude Opus 4.7 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant