Mengapa (falsifiable — diverifikasi 2026-07-17)
Snapshot CodeLens menyimpan edge call-graph ke disk tapi tidak pernah membandingkannya. _diff_backend() (scripts/diff_engine.py:303-353) hanya membaca nodes — kata edges tidak muncul sekali pun di seluruh fungsi itu, padahal _empty_backend() (baris 204-205) mendeklarasikan {"nodes": [], "edges": []} dan save_snapshot() men-deepcopy seluruh dict backend.
Repro (snapshot nyata di repo ini, scripts/.codelens/snapshots/20260714T080003Z.json):
backend keys: ['last_updated', 'workspace', 'nodes', 'edges']
nodes: 2429 edges: 25876
| Data di snapshot |
Dibandingkan oleh _diff_backend()? |
| 2.429 nodes |
✅ ya (added/removed/changed + new_dead/resolved_dead) |
| 25.876 edges |
❌ tidak — diabaikan total |
Akibatnya impact --check diff bisa bilang "fungsi X jadi dead", tapi tidak bisa bilang:
- edge baru muncul dari modul A ke modul B (arsitektur melar diam-diam)
- edge X→Y hilang (perilaku berubah tanpa fungsi mana pun hilang)
Perubahan struktural yang tidak menghapus/menambah fungsi = tak terlihat sepenuhnya hari ini. Padahal datanya sudah ada di disk.
Mekanisme (dari inspeksi data snapshot, bukan asumsi)
Edge tidak seragam bentuknya — ada 3 shape, dan ini menentukan desain:
| Shape |
Jumlah |
Arti |
{from, to_fn, resolved:false} |
21.323 |
call tak ter-resolve (target = nama saja) |
{from, to} |
3.669 |
call ter-resolve (to = node id) |
{from, to, via_self} |
884 |
call ter-resolve via self.x() |
Fakta terukur yang membentuk constraint:
- 82% edge tak ter-resolve. Target teratasnya:
get, append, group, strip, join, startswith, search, match — method builtin/stdlib. Nol nilai arsitektural.
- Resolved edge: 4.553 total tapi hanya 3.309 pasangan
(from,to) unik — 547 pasangan berulang (maks 26×), karena satu edge dicatat per call-site.
via_self bernilai True (884) atau absen (3.669) → kualifier, bukan bagian identitas.
Konsekuensi: diff naif atas 25.876 edge = sampah (21k noise builtin), dan diff sebagai multiset akan melaporkan "berubah" hanya karena jumlah call-site bergeser — padahal bentuk graph sama.
Konteks
Tujuan
_diff_backend() membandingkan bentuk call-graph, bukan cuma keberadaan fungsi. Setelah ini, satu perintah bisa menjawab: "edge apa yang muncul/hilang antara dua checkpoint?"
Constraint
- Identitas edge = pasangan
(from, to) unik atas resolved edge saja. Set, bukan multiset — perubahan jumlah call-site bukan perubahan arsitektur.
- Unresolved edge (
to_fn) TIDAK masuk detail diff — hanya delta jumlah. 21k append/strip/get akan menenggelamkan sinyal.
via_self dikeluarkan dari kunci identitas (kualifier).
- Count selalu eksak; list detail dibatasi (cap) + flag
truncated — 3.309 pasangan bisa meledak jadi ribuan entri saat file di-rename.
- Backward compatible: field lama (
added_nodes, removed_nodes, changed_nodes, *_count, new_dead, resolved_dead) tidak boleh berubah bentuk/nama — commands/diff.py, dashboard.py, formatter, dan MCP mengonsumsinya.
- Snapshot lama (tanpa key
edges, atau shape campur) harus di-handle tanpa crash → .get("edges", []).
- Zero dead code. Tidak ada command baru — command count tetap 12.
- Bukan feature-class file baru (engine sudah ada) → tidak butuh design doc; PR pakai label
skip-design-doc bila CI meminta.
Definition of Done
Mengapa (falsifiable — diverifikasi 2026-07-17)
Snapshot CodeLens menyimpan edge call-graph ke disk tapi tidak pernah membandingkannya.
_diff_backend()(scripts/diff_engine.py:303-353) hanya membacanodes— kataedgestidak muncul sekali pun di seluruh fungsi itu, padahal_empty_backend()(baris 204-205) mendeklarasikan{"nodes": [], "edges": []}dansave_snapshot()men-deepcopy seluruh dict backend.Repro (snapshot nyata di repo ini,
scripts/.codelens/snapshots/20260714T080003Z.json):_diff_backend()?Akibatnya
impact --check diffbisa bilang "fungsi X jadi dead", tapi tidak bisa bilang:Perubahan struktural yang tidak menghapus/menambah fungsi = tak terlihat sepenuhnya hari ini. Padahal datanya sudah ada di disk.
Mekanisme (dari inspeksi data snapshot, bukan asumsi)
Edge tidak seragam bentuknya — ada 3 shape, dan ini menentukan desain:
{from, to_fn, resolved:false}{from, to}to= node id){from, to, via_self}self.x()Fakta terukur yang membentuk constraint:
get,append,group,strip,join,startswith,search,match— method builtin/stdlib. Nol nilai arsitektural.(from,to)unik — 547 pasangan berulang (maks 26×), karena satu edge dicatat per call-site.via_selfbernilaiTrue(884) atau absen (3.669) → kualifier, bukan bagian identitas.Konsekuensi: diff naif atas 25.876 edge = sampah (21k noise builtin), dan diff sebagai multiset akan melaporkan "berubah" hanya karena jumlah call-site bergeser — padahal bentuk graph sama.
Konteks
impact --check diff→commands/diff.py→diff_engine.diff_snapshots()/diff_current_vs_last().save_snapshot(),list_snapshots(),_load_snapshot(), retensi 20 terakhir (_cleanup_old_snapshots). 7 snapshot nyata ada di repo.deps --check export-snapshot/import-snapshot(chore(deps): import-snapshot permanently broken since export-snapshot was dropped #218) round-trip sudah terverifikasi.Tujuan
_diff_backend()membandingkan bentuk call-graph, bukan cuma keberadaan fungsi. Setelah ini, satu perintah bisa menjawab: "edge apa yang muncul/hilang antara dua checkpoint?"Constraint
(from, to)unik atas resolved edge saja. Set, bukan multiset — perubahan jumlah call-site bukan perubahan arsitektur.to_fn) TIDAK masuk detail diff — hanya delta jumlah. 21kappend/strip/getakan menenggelamkan sinyal.via_selfdikeluarkan dari kunci identitas (kualifier).truncated— 3.309 pasangan bisa meledak jadi ribuan entri saat file di-rename.added_nodes,removed_nodes,changed_nodes,*_count,new_dead,resolved_dead) tidak boleh berubah bentuk/nama —commands/diff.py,dashboard.py, formatter, dan MCP mengonsumsinya.edges, atau shape campur) harus di-handle tanpa crash →.get("edges", []).skip-design-docbila CI meminta.Definition of Done
_diff_backend()mengembalikanadded_edges,removed_edges(resolved-only, distinct(from,to), capped +truncated) danadded_edge_count/removed_edge_count(eksak)unresolved_countfrom→to), tanpa detail per-edgesummarydidiff_snapshots()dandiff_current_vs_last()menyertakanedges_added/edges_removedimpact --check difftetap hijauedgestidak crash (backward compat)added_edges; edge dihapus → muncul diremoved_edges; call-site bertambah tanpa pasangan baru → tidak dilaporkan; unresolved edge tidak bocor ke detailCoretax-Auto-Downloader/smart-tax-assistance/app, 425 file): dua checkpoint + satu perubahan nyata → edge delta benar