GitNexus/gitnexus/test
Carter LaSalle f34daea86a
fix(routes): connect decorator routes to their handler function (#2865)
* fix(routes): connect decorator routes to their handler function

A Route node's only relationship was HANDLES_ROUTE from its FILE. The graph knew
a route existed and which file declared it, but not which function implemented
it. Two consequences on a 12.4k-file repository with 162 FastAPI routes:

  - Every decorated handler was indistinguishable from dead code. Its sole edge
    was DEFINES, so a reachability query reported it unreferenced even though the
    framework invokes it on every request.
  - `route_map` / `api_impact` could only answer at file granularity, and
    `processes.ts` routed every route through its `routesWithoutHandlerByFile`
    fallback instead of keying by handler.

Two halves of one gap, both already designed for and neither wired:

1. `ExtractedDecoratorRoute.handlerName` is documented as "captured at extraction
   where the decorated definition node is in hand", and `resolveRouteHandlerSymbols`
   already consumes it to stamp `handlerSymbolId`. Only the Spring extractor ever
   set it, so for every decorator-routed framework — FastAPI, Flask, NestJS — it
   arrived undefined and 0 of 162 routes carried a handler. A route decorator's
   parent IS the decorated definition, so the name is in hand: add
   `decoratedDefinitionName` and thread it through. It climbs consecutive
   decorators so stacked forms (`@router.get(...)` over `@requires_auth`) resolve,
   caps the climb so a malformed tree cannot loop, and returns undefined rather
   than guessing — the routes phase already treats a missing name as
   "fall back to file-level".

2. With a handler symbol resolved there is finally something to point an edge at.
   Emit a definition-level HANDLES_ROUTE alongside the file-level one. The sibling
   decorator overlay already does exactly this: `pipeline-phases/tools.ts` anchors
   HANDLES_TOOL on the definition the decorator sat on, not its file. Routes were
   the outlier.

Kept as one change because the edge is inert without the symbol — emitted from a
branch lacking part 1 it produces zero edges, since `handlerSymbolId` is empty.

Additive, and both existing consumers are unaffected:
`group/extractors/http-route-extractor.ts` types its query `(handlerFile:File)`;
`manifest-extractor.ts` matches an untyped `(handler)` but takes `LIMIT 1` ordered
by `handler.id`, and `File:…` sorts before `Function:…`, so its selected row is
unchanged.

Direction is Function → Route, matching how every other overlay attaches
(MEMBER_OF → Community, STEP_IN_PROCESS → Process, HANDLES_TOOL → Tool: the symbol
is the source). That also keeps it free of schema risk — `Function|Route` is
already declared by the ATTACHMENT rule in `lbug/schema.ts`
(`DEFINITION_ANCHOR_LABELS × ATTACHMENT_TARGET_LABELS`), which that file documents
as deliberate headroom for this case. Route → Function would have needed a new
hand-listed pair, and an undeclared pair aborts `analyze` outright — a failure
that file records having hit four separate times.

Verified on a FastAPI fixture (edges 9 → 11):
  api.py        (File)    -> GET /widgets, POST /widgets   [unchanged]
  list_widgets  (line 10) -> GET  /widgets                 [new]
  create_widget (line 15) -> POST /widgets                 [new]

On the 12.4k-file repository: 161 of 162 routes now resolve to their handler
function, up from 0. The single abstention is `uniqueSymbolId` correctly refusing
to guess where the name is not uniquely resolvable in its file.

`npx tsc --noEmit` clean; schema-pair coverage and route suites pass (196 tests).

* fix(routes): harden decorator handler attribution (#2865)

Keep definition-level route links correct across warm caches and malformed symbol lookups, and avoid per-route group-sync scans. Move Python AST ownership behind the language provider and add end-to-end regression coverage.

Note: full npm test could not complete in this container due unrelated worker startup failures and a stalled retry; targeted route suites, typecheck, format, and lint passed.
Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor(routes): reuse per-file symbol lookup and drop duplicate warm-cache test

Share extract()'s CONTAINING_QUERY memo with the graph provider path, resolve each route handler once, and fold the decorator-edge warm-cache assertions into the existing FastAPI composed-route round-trip.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Carter LaSalle <carterlasalle@gmail.com>
Co-authored-by: Gergő Magyar <gergomagyar@icloud.com>
Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-01 14:03:30 +00:00
..
fixtures feat(ingestion): capture Spring handler annotation arguments and template publishes (#3128) 2026-09-01 14:35:19 +01:00
helpers fix(ingestion): ignore emitted Next.js build output, and delete the inert public/build entry (#3018) 2026-08-27 13:29:05 +01:00
integration fix(routes): connect decorator routes to their handler function (#2865) 2026-09-01 14:03:30 +00:00
unit fix(routes): connect decorator routes to their handler function (#2865) 2026-09-01 14:03:30 +00:00
utils fix(hook): emit MCP query hint when server owns DB lock (#2396) (#2397) 2026-07-08 18:34:05 +01:00