Skip to content

fix(callgraph): reference_count severely undercounts cross-file calls #210

Description

@Wolfvin

Context

Ditemukan saat audit CodeLens terhadap codebase nyata (Coretax-Auto-Downloader, vps-deploy/api/kds backend). reference_count (field rc di output search) yang menjadi basis banyak command (dead-code, impact, trace ref_count) ternyata SALAH — undercounting parah, bukan cuma di kasus edge (0 vs beberapa).

Mengapa

Dua bukti konkret dari real codebase:

  1. requirePermission (middleware factory, src/middleware/permission-gate.ts:56) — rc: 0 di output search --mode symbol. Ground truth: dipanggil di 13+ file sebagai requirePermission('admin') yang dipassing sebagai argument ke route registration (router.post(path, requirePermission('admin'), handler)). Verified via SQLite langsung: SELECT * FROM graph_edges WHERE target_id LIKE '%requirePermission%' → 0 rows. Tidak ada satupun CALLS edge terbentuk.

  2. hasPermission (src/lib/permissions.ts:75) — rc: 1. Ground truth via grep (exclude comment lines): 7 real call sites di assignments.ts (3x) dan task-templates.ts (3x) plus 1x di permission-gate.ts. rc seharusnya 7, bukan 1.

Kedua kasus menunjukkan call-graph builder (scripts/callgraph_engine.py, Phase 3 _resolve_call() dan resolusi edge di sekitar baris 590-610) tidak reliable untuk cross-file call counting — entah under-resolve import cross-file, entah dedup logic yang salah collapse banyak call site jadi satu edge, atau miss calls yang dipassing sebagai argument ke call lain (middleware factory pattern).

Konteks

Field ref_count/rc dipakai di banyak tempat: search result ranking, dead-code (ref_count == 0 sebagai basis "possibly dead"), impact (jumlah dependent). Kalau undercounting ini luas, confidence semua command tersebut ikut tidak reliable — worker perlu investigasi apakah ini kasus terisolasi (khusus middleware-factory-argument pattern) atau sistemik (semua cross-file call undercounting).

Tujuan

  1. Investigasi root cause: kenapa CALLS edge tidak terbentuk untuk call yang dipassing sebagai argument (requirePermission('admin') di dalam router.post(...)), dan kenapa hasPermission yang dipanggil 7x hanya tercatat 1x
  2. Fix root cause di callgraph_engine.py — kemungkinan di traversal (_walk recursion ke argument dari call_expression lain), resolusi (_resolve_call), atau edge dedup logic
  3. Pastikan fix tidak regress command lain yang depend pada graph (impact, trace, dead-code sudah baru saja di-fix minggu ini — jangan buat regresi baru di sana)

Constraint

  • Baca dulu _parse_calls_treesitter (baris ~1589) dan _resolve_call (baris ~2055) sebagai starting point — TAPI investigasi mandiri, jangan asumsikan lokasi bug ada di situ tanpa verifikasi
  • Test terhadap 2 kasus di atas sebagai regression test minimal
  • Jangan ubah command files (commands/*.py) kecuali memang diperlukan — fix seharusnya cukup di callgraph_engine.py atau file engine terkait
  • Setelah fix, re-run dead-code, impact, trace di codebase yang sama untuk pastikan tidak ada regresi (angka-angka boleh berubah karena lebih akurat, tapi commandnya harus tetap jalan tanpa crash)

Definition of Done

  1. search "requirePermission" <kds-path> --mode symbol menunjukkan rc >= 13 (atau jumlah real call site yang benar)
  2. search "hasPermission" <kds-path> --mode symbol menunjukkan rc == 7 (atau jumlah real call site yang benar, exclude comments)
  3. Root cause didokumentasikan di PR description — bukan cuma "sudah fixed" tanpa penjelasan kenapa
  4. python -m pytest tests/ -k "callgraph or ref_count" — 0 regresi baru
  5. Minimal 1 unit test baru yang reproduce kedua kasus di atas (middleware-factory-argument pattern + multi-site same-file calls)

Checklist Laporan Worker

  • Root cause detail: bagian mana di callgraph_engine.py yang salah dan kenapa
  • rc value untuk requirePermission dan hasPermission sebelum dan sesudah fix
  • Hasil test suite lengkap (bukan cuma yang terkait callgraph)
  • Re-test dead-code/impact/trace di KDS backend — screenshot/output before-after untuk pastikan tidak regresi

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions