fix(scan): stop misclassifying .ts in routes/public/ as TSX (closes #231)#263
Merged
Merged
Conversation
) Issue #231 reported getGoogleClient showing rc:0 in search --mode symbol even though TSBackendParser.extract_references() correctly emits the edge in isolation. The issue hypothesised the bug was in graph_model.populate_graph_tables() (baris ~330-375). Investigation proved the bug was UPSTREAM — in commands.scan.is_frontend_file and is_backend_file. The matching logic used: if normalized.startswith(fp_norm) or f"/{fp_norm}" in normalized or normalized == fp_norm: The second check (f"/{fp_norm}" in normalized) matched ANY path containing the frontend_path as a MIDDLE segment. For src/routes/public/customer-auth.ts (a backend route file), the path contains /public/ as a middle segment, so is_frontend_file returned True and the file was misclassified as TSX (frontend). The TSX frontend parser does not extract backend call-graph edges, so all 5 edges from customer-auth.ts (including the asyncHandler-wrapped call to getGoogleClient) were silently dropped before reaching backend.json / graph_edges. Fix: remove the middle-segment check from both is_frontend_file and is_backend_file. Frontend/backend paths are workspace-root-relative directory prefixes — they should ONLY match paths that start with the prefix. should_ignore is different: it intentionally matches middle segments (node_modules can be nested in monorepos), but frontend_paths/backend_paths identify the workspace-root directory. After fix: - getGoogleClient rc: 0 -> 1 (search --mode symbol) - customer-auth.ts categorized as js_backend (TS backend parser), not tsx - requirePermission rc (issue #219 pattern) unchanged — no regression Root cause location differs from issue hypothesis — see Catatan Pendekatan in PR description. Regression tests: tests/test_issue231_async_handler_edges.py (16 tests) - Unit: is_frontend_file/is_backend_file segment matching (6 tests) - Integration: discover_files categorization (1 test) - End-to-end: asyncHandler-wrapped edge reaches backend.json + graph_edges + ref_count >= 1 (4 tests) - #219 regression safeguard: direct-argument pattern still works (2 tests) - Pre-existing edge cases: nested public/, windows backslash, etc. Verified against clean baseline (commit c722f4a): 0 new failures. Baseline: 9 failed, 2357 passed. Branch: 5 failed (all pre-existing), 2410 passed (53 more — 16 new + 37 from main progress since c722f4a).
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Closed
4 tasks
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Closes #231
Patch Peta (delta struktural)
Files:
~ scripts/commands/scan.py —
is_frontend_file/is_backend_fileno longer match frontend/backend paths as middle path segments (only workspace-root-relative prefix). Fixes the root cause of #231.Endpoints: none
Schema: none
Konvensi:
frontend_paths/backend_pathsin codelens.config.json are workspace-root-relative directory prefixes. They match only paths that START WITH the prefix — NOT paths that contain the prefix as a nested segment. This is DIFFERENT fromshould_ignore(which intentionally matches middle segments —node_modulescan be nested in monorepos). Any future change to path categorization must preserve this distinction.Klaim + Bukti
Root cause isolated (different from issue hypothesis)
The issue hypothesised the bug was in
graph_model.populate_graph_tables()(baris ~330-375). Investigation proved the bug was UPSTREAM — incommands.scan.is_frontend_file/is_backend_file.The buggy matching logic:
Check #2 (
f"/{fp_norm}" in normalized) matched ANY path containing the frontend_path as a MIDDLE segment. Forsrc/routes/public/customer-auth.ts, the path contains/public/→is_frontend_filereturned True → file misclassified as TSX (frontend). The TSX frontend parser does NOT extract backend call-graph edges, so all 5 edges fromcustomer-auth.ts(including the asyncHandler-wrapped call togetGoogleClient) were silently dropped before reachingbackend.json/graph_edges.End-to-end verification (minimal repro mimicking KDS pattern)
Repro workspace:
src/routes/public/customer-auth.tswithcustomerAuthRouter.post('/auth/google', asyncHandler(async (req, res) => { ... getGoogleClient() ... }))+src/services/google.tsdefininggetGoogleClient.Result (after fix):
{ "s": "ok", "r": [ { "name": "getGoogleClient", "ref_count": 1, "location": "src/services/google.ts:4", ... } ] }ref_count: 1— DoD #1 satisfied. Pre-fix this wasref_count: 0.SQLite graph_edges verification (correct query — issue's query was flawed)
The issue used
SELECT ... WHERE target_id LIKE '%getGoogleClient%'which returns 0 rows even when the edge exists, because resolved edges storetarget_id = file:line(no fn name) and unresolved edges storetarget_id = NULLwithto_fninextra_json.Correct query (after fix):
Result: 1 row,
source_id='src/routes/public/customer-auth.ts:0:<module>', target_id='src/services/google.ts:4', edge_type=CALLS.#219 regression check (direct-argument pattern)
Result:
"ref_count": 1— unchanged from pre-fix behavior. The #219 pattern (router.post(path, requirePermission('admin'), handler)— direct argument) was already working and is not regressed by the #231 fix.File categorization verification
Pre-fix:
customer-auth.tsinfiles['tsx'](frontend — WRONG).Post-fix:
customer-auth.tsinfiles['js_backend'](backend — CORRECT, parsed by TSBackendParser).Test suite
Result:
5 failed, 2410 passed, 96 skipped in 44.69s.Regression verification (methodology per CONTEXT.md)
Cloned clean baseline at commit
c722f4a(last commit before this session), ran the same 5 failing tests against it:Baseline result:
5 failed— IDENTICAL failures (same assertion errors, same test names). All 5 are pre-existing, verified 100% not caused by this PR.Baseline full suite:
9 failed, 2357 passed, 76 skipped.Branch full suite:
5 failed, 2410 passed, 96 skipped.Delta: +53 passed (16 new tests + 37 from main's progress since c722f4a), -4 failed (4 test_adr failures fixed by main's progress, not by this PR), +20 skipped. Zero new failures introduced.
New regression tests (16 tests, all passing)
Result:
16 passed in 0.60s.Coverage:
is_frontend_file/is_backend_filesegment matching (6 tests — root match, nested rejection, windows backslash)discover_filescategorization (1 test —customer-auth.tsinjs_backend,App.tsxstill intsx)backend.json+graph_edges+ref_count >= 1(4 tests)public/,packages/app/src/, unrelated paths (3 tests)Command count unchanged
Result:
6 passed in 1.73s. No command added/removed — count stays at 12 umbrella + plugin.Catatan Pendekatan
Issue #231 menyarankan bug ada di
graph_model.populate_graph_tables()(baris ~330-375, tempat prosesflat_edgessebelum insert kegraph_edgestable). Saya menggunakan pendekatan investigasi mandiri (sesuai constraint issue: "jangan asumsikan bug ada di titik yang sudah disebutkan tanpa verifikasi ulang") dan membuktikan bug ada UPSTREAM — dicommands.scan.is_frontend_file/is_backend_file.Investigasi end-to-end: parser →
resolve_edges()→backend.json→populate_graph_tables()→graph_edges.Temuan:
TSBackendParser.extract_references) — VERIFIED BENAR. Memproduksi 5 edge daricustomer-auth.ts, termasuk→ getGoogleClient.resolve_edges()— VERIFIED BENAR. Semua 5 edge dipertahankan (1 resolved kesrc/services/google.ts:4, 4 unresolved).backend.json— BUG: hanya 1 edge total (dariasyncHandler.ts), 5 edge daricustomer-auth.tsHILANG.graph_edges— KONSEKUENSI: edgegetGoogleClienttidak ada (karena tidak pernah sampaibackend.json).Root cause:
customer-auth.tsmisclassified sebagai TSX (frontend) olehis_frontend_file, karena pathsrc/routes/public/customer-auth.tsmengandung/public/sebagai middle segment.frontend_pathsdefault termasukpublic/, dan check #2 (f"/{fp_norm}" in normalized) match middle segment. TSX frontend parser tidak extract backend call-graph edges.Outcome yang dicapai tetap sesuai Definition of Done:
search "getGoogleClient" --mode symbolmenunjukkanrc >= 1(sekarangrc: 1)populate_graph_tables)requirePermissionrc tidak turun (masih1di repro — pola direct-argument fix(callgraph): extract module-top-level calls to fix rc undercount (closes #210) #219 tetap benar)c722f4a)Breaking / Found-not-fixed
none
Catatan untuk BOS: issue #231 body mengklaim edge "TIDAK ADA di SQLite" berdasarkan query
SELECT ... WHERE target_id LIKE '%getGoogleClient%'. Query ini metodologisally flawed —target_iduntuk resolved edge menyimpanfile:line(tanpa fn name), dan untuk unresolved edgetarget_id = NULLdenganto_fndiextra_json. Query seperti itu akan return 0 rows bahkan kalau edge ada. Investigasi ini menggunakan query yang benar (WHERE target_id = '<node_id>'atauWHERE extra_json LIKE '%getGoogleClient%') dan mengkonfirmasi edge memang hilang — tapi root cause-nya di file categorization, bukan di SQLite write layer.