為什麼這九個 patch 值得學
v0.9.57~v0.9.65(2026-09-09 至 2026-09-20)延續 Graphify 一貫的主題:知識圖譜的價值取決於邊的可信度。這批 patch 修的都是「圖看起來建好了,但內容默默地錯了」的問題——增量重建丟節點、 dangling edge 物化成幻影、合併時資訊較少的節點贏過較完整的。
Terraform 進圖(v0.9.62、v0.9.64)
兩個版本把 Terraform 從「文字檔」變成「拓撲」:
模組呼叫拓撲(v0.9.62,#3571)
module call 帶字面 local source(./… 或 ../…)時,現在解析到 directory-scoped module node,揭露 caller → implementation 的分層(例如 environment → application → base)。
保守邊界不變:remote 與 registry source、以及任何 source 運算式都不猜、不偽造目標。
屬性保留與 secret redaction(v0.9.64,#3644)
resource / data / module node 現在保留 block attributes(ami、instance_type、cidr_block、tags 等),帶型別(bool/number/list/map)、nested block 與直接屬性分開,可查詢可搜尋。
安全設計:secret 命名的屬性值在進入 graph.json 或模型之前先 redact——password、*secret*、*token*、*_key、連線字串都算。寫死在 .tf 檔裡的 credential 不會因為建圖而外洩。
升級既有 graph 後,跑一次
graphify update .重建 Terraform id 與拓撲。
Dangling Edge 的終結者:External Stub Node(v0.9.63)
過去 graph.json 裡 imports / imports_from / re_exports 邊的端點可能指向外部模組(stdlib、第三方套件)——一個從未宣告過的節點。載入器(loader)會把這種 dangling endpoint 物化成沒有屬性的幻影節點。
v0.9.63 起:
- 對外部模組的邊改為鑄造 typed external stub node(有類型的外部存根節點)
graph.json裡每條邊的每個端點都保證是宣告過的節點- 跨 repo merge 把同一個外部模組統一成單一 global node
「不變式(invariant)寫進格式」比「載入器要記得處理例外」可靠——這是把正確性從慣例升級為結構。
增量重建不再丟節點(v0.9.57、v0.9.59、v0.9.65)
三個 patch 分別堵住三條靜默丟失路徑:
| 版本 | 問題 | 修法 |
|---|---|---|
| v0.9.57(#3411) | 重萃取一個 .csproj/.sln 會丟掉被參照專案的 package/framework 節點 |
AST-replacement set 改從實際萃取的檔案推導 |
| v0.9.59(#3477) | 增量重建丟掉未觸及檔案的 cross-file concept 節點 |
merge 時的 global dedup 保護未觸及檔案的既有節點 |
| v0.9.65 | eviction pass 剛報告「保留」的節點又被清除;moved-file/symlink layout 會把 shrink guard 卡死到拒絕每次 update | eviction pass 重查 kept set |
共同教訓:增量系統的 bug 通常不是「更新了不該更新的」,而是「以為自己沒動到的其實動到了」。
跨檔 Resolution 擴充(v0.9.58~v0.9.65)
這批語言層的改進全部遵循同一個原則:只在無歧義時才連邊。
- Ruby:隱式 self 呼叫與已知型別 receiver 的 member call,可沿單一無歧義繼承鏈升級到 superclass method(#3569、#3585);mixin、reopened class、動態 superclass 一律不猜
- Rust:
self.method()跨檔解析到 split-impl 同型別的 method(v0.9.63,#3602);v0.9.64 擴及簡單 generic impl(impl<T> Foo<T>),bounded /where/ trait 形狀仍 fail-closed(#3653) - Kotlin:receiver 呼叫跨檔解析到另一檔宣告的
object/ class /companion object(#3598) - C++:scope-qualified static call
Foo::bar()跨 translation unit 解析(#3613) - Go / Swift:interface 的 method requirements(
type Foo interface { Bar() })與 protocol 的func f()附加到 interface / protocol 節點本身(#3672、#3673) - Elixir:
alias/import/require/use解析到defmodule節點,模組依賴圖不再是 dangling(#3603);僅頂層模組索引 - Python:巢狀函式依 lexical scope 解析(#3410);PEP 420 namespace package 子模組 import(#3429);同層平目錄 bare-name import 模擬
sys.path[0](#3430) - JS/TS:
let/const綁定改為 block-scoped——block-local 綁定不再壓制同函式其他地方真實的indirect_call邊;var維持 function-scoped(v0.9.65,#3688) - PHP:
use Foo\Bar as Baz;以 alias 為 key,後續Baz解析到真實 class(#3421);檔內 inline<script>以 JS 索引並映射回真實行號(#3627) - Java / Verilog:enum body member 掛回 enum 節點、enum 內部呼叫可解析(#3674);module instantiation 連本地定義而非幻影重複(#3675)
Markdown 參考邊(v0.9.62,#3562)
文件裡的 inline code span(例如 `Widget.render`)在整個 corpus 恰有一個 callable 匹配時,發出 references 邊。generic 詞彙與歧義名稱不連——文件加入圖,而不產生假邊洪流。
另外:檔名是裸複數「tokens」的文件(如 TOKENS.md)不再被誤判為 credential dump(#3527)。
效能與可攜性
- Python symbol resolution 快約 47%(v0.9.59):path resolution memoize、每檔跨兩個 pass 只解析一次、tree walk 改迭代式
- Python 3.12 / 3.13:
graphify.serve可正常 import;chineseextra 自 3.12 起改 pinjieba-py(v0.9.61) - Python 3.14 支援(v0.9.60)
- Windows:atomic write 在
WinError 17(跨磁碟區)正確 fallback(v0.9.60) - 可見性:無法分類的檔案以計數與 top extensions 呈現,不再從「成功」run 中消失(#3511)
安全(v0.9.65,#3698)
svg / all extras 對 Pillow 加下限 >=12.3.0,修 CVE-2026-54058(Pillow 經 matplotlib 間接被拉入)。
注意:Pillow 12.3.0 已不提供 glibc < 2.27 的 cp310 Linux wheel——老舊 glibc + Python 3.10 主機裝這兩個 extra 時會從 sdist 建置。
升級建議
| 情境 | 建議 |
|---|---|
| 有 Terraform | 必跑 graphify update .(重建 module id 與拓撲) |
| 依賴 Rust / Kotlin / Ruby 繼承鏈、Elixir module graph | 建議 rebuild |
svg / all extra + 老 glibc |
注意 Pillow 可能從 sdist 建置 |
| 其他 | 一般升級即可,增量索引延續 |